سؤال

لدي برنامج مخفي يقرأ ملف التكوين من أجل معرفة مكان كتابة شيء ما. في ملف التكوين، يوجد سطر مثل هذا:

output = /tmp/foo/%d/%s/output

أو قد تبدو مثل هذا:

output = /tmp/foo/%s/output/%d

... أو ببساطة مثل هذا:

output = /tmp/foo/%s/output

... أو أخيرا:

output = /tmp/output

لدي هذا الخط ك CFG-> PathFmt داخل برنامجي. ما أحاول فعله الآن هو التوصل إلى بعض طريقة ذكية لاستخدامها.

أكثر قليلا من التفسير، يمكن أن يحتوي المسار على مكونين يصل إلى عنصرين. سيتم توسيع٪ D كمعرف وظيفة (INT)،٪ S كاسم وظيفة (سلسلة). قد يرغب المستخدم في استخدام واحد أو لا شيء في ملف التكوين. أحتاج إلى معرفة ما يريدون وفي أي ترتيب قبل أن تمر أخيرا إلى SPRINTF (). يمكنني تضييق نوعها، لكنني أظل الرغبة في التحدث إلى Strtok () وهذا يبدو قبيحا.

أريد أن أعطي المستخدمين هذا النوع من المرونة، ومع ذلك فقد فقد فقد تبحث عن طريقة معقولة ومحمولة لتنفيذها. أنا أيضا في خسارة كاملة ومجموعة لكيفية البدء في البحث عن هذا.

سأكون سعيدا جدا إذا:

  • يمكن لأي شخص أن يساعدني في تضييق عبارة البحث لإيجاد أمثلة جيدة
  • شخص ما يمكن أن ينشر رابطا لبعض مشروع OSS ينفذ هذا
  • شخص ما يمكن نشر بعض رمز psuedo

لا أريد الكود المكتوب بالنسبة لي، أنا فقط عالق في ما (أعتقد) أن يكون شيئا بسيطا للغاية وتحتاج إلى بعض المساعدة في تناول الدقات الأولى. أشعر حقا كأنني أفكر وتطل على الواضحة.

يجب أن تكون النتيجة النهائية وظيفة منطقية مثل هذا:

bool output_sugar(const char *fmt, int jobid, const char *jobname, struct job *j);

بعد ذلك، اتصل ب SPRINTF () (بشكل معقول) على J-> Outpath، عودة False إذا كان نوعا من القمامة (أي٪ متبوعا بشيء لا S أو D أو٪) موجود في خط التكوين (أو NULL). الشيكات العقلية سهلة، أنا فقط في الحصول على القليل من الوقت في الحصول على رقم (والنظام) من الحجج للتنسيق الصحيح.

شكرا مقدما. أيضا، لا تتردد في تحرير هذا العنوان إذا كان لديك سمعة للقيام بذلك، كما قلت، لست متأكدا تماما من كيفية طرح السؤال في سطر واحد. أعتقد ما أحتاجه هو محلل, ، ولكن يبدو محرجا باستخدام Lexer / محلل في مهب كامل للتعامل مع سلسلة واحدة بسيطة.

هل كانت مفيدة؟

المحلول

نعم، تحتاج إلى محلل من نوع ما. لا تحتاج إلى أن تكون معقدة، رغم ذلك:

void format_filename(const char *fmt, int jobid, const char *jobname,
                     char *buffer, size_t buflen)
{
    char *end = buffer + buflen - 1;
    const char *src = fmt;
    char *dst = buffer;
    char c;
    assert(buffer != 0 && fmt != 0 && buflen != 0 && jobname != 0);
    while ((c = *src++) != '\0')
    {
        if (dst >= end)
            err_exit("buffer overflow in %s(): format = %s\n",
                     __func__, fmt);
        else if (c != '%')
            *dst++ = c;
        else if ((c = *src++) == '\0' || c == '%')
        {
            *dst++ = '%';
            if (c == '\0')
                break;
        }
        else if (c == 's')
        {
            size_t len = strlen(jobname);
            if (len > end - dst)
                err_exit("buffer overflow on jobname in %s(): format = %s\n",
                         __func__, fmt);
            else
            {
                strcpy(dst, jobname);
                dst += len;
            }
        }
        else if (c == 'd')
        {
             int nchars = snprintf(dst, end - dst, "%d", jobid);
             if (nchars < 0 || nchars >= end - dst)
                 err_exit("format error on jobid in %s(); format = %s\n",
                          __func__, fmt);
             dst += nchars;
        }
        else
            err_exit("invalid format character %d in %s(): format = %s\n",
                     c, __func__, fmt);
    }
    *dst = '\0';
}

الآن اختبار رمز. لاحظ أنه يدعم تدوين "٪٪" للسماح للمستخدم بتضمين "٪" واحد في الإخراج. أيضا، يعالج "٪" واحد في نهاية السلسلة ساري المفعول ويعادل "٪٪". يستدعي Err_Exit () عند الخطأ؛ يمكنك اختيار استراتيجيات خطأ بديلة لأنها تناسب النظام الخاص بك. أنا ببساطة افترض أنك شملت <assert.h>, <stdio.h> و <string.h> والرأس ل err_exit() (variadic) وظيفة.


رمز الاختبار ...

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>

static void err_exit(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    exit(1);
}

... ومن بعد format_filename() على النحو الوارد أعلاه، ثم ...

#define DIM(x) (sizeof(x)/sizeof(*(x)))

static const char *format[] =
{
    "/tmp/%d/name/%s",
    "/tmp/%s/number/%d",
    "/tmp/%s.%d%%",
    "/tmp/%",
};

int main(void)
{
    char buffer[64];
    size_t i;

    for (i = 0; i < DIM(format); i++)
    {
        format_filename(format[i], 1234, "job-name", buffer, sizeof(buffer));
        printf("fmt = %-20s; name = %s\n", format[i], buffer);
    }

    return(0);
}

نصائح أخرى

باستخدام Strtok هو خطأ عرضة. يمكنك علاج المتغيرات الخاصة بك ككلغة صغيرة باستخدام (FL) LEX و YACC. هناك برنامج تعليمي بسيط هنا

%{
#include <stdio.h>
%}

%%
%d                      printf("%04d",jobid);
%s                      printf("%s",stripspaces(dirname));
%%

قمت بإجراء غلاف ODBC الذي سيتيح لك أن تفعل أشياء مثل DBPRINTF ("إدراج في قيم بلاه٪ S٪ S٪ T٪ Y"، أشياء هنا ...)؛ لكنها منذ سنوات عديدة وقمت بتحليل سلسلة التنسيق باستخدام Strtok.

إذا كان عدد الخيارات الصغيرة ولا تريد خلاف ذلك / تحتاج إلى المرونة الإضافية وتعقيد المحلل المحلل، فيمكنك ببساطة البحث عن كل فرعية استبدال محتملة باستخدام STRSTR ().

إذا كان لديك الخيارين فقط، فيمكنك إنشاء بنية أكثر تتراوح بين أربعة متفرعات (فقط، فقط B، كلاهما مع A قبل B، كلاهما مع B قبل أ) لاستدعاء Sprinth () مع الطلب بشكل صحيح الحجج. خلاف ذلك، قم بإجراء مكالمات SPRINTF () متعددة ()، يحل كل منها محل كل واحد فقط من علامة الاستبدال فقط في سلسلة التنسيق. (هذا يعني بناء قائمة بدائل مطلوبة وفرزها في ترتيب المظهر ...)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top