سؤال

كيفية سلامة الحاجز سلسلة tab-delimiter؟ على سبيل المثال: اختبار tbla-bla-bla t2332؟

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

المحلول

strtok() هي وظيفة قياسية لحلية السلاسل مع المحددات التعسفية. ومع ذلك ، فهي ليست آمنة الخيط. قد تحتوي مكتبة C الخاصة بك على متغير آمن مؤشر ترابط.

طريقة أخرى متوافقة مع المعيار (كتبت هذا الأمر فقط لم تختبر):

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

int main()
{
    char string[] = "foo\tbar\tbaz";
    char * start = string;
    char * end;
    while ( ( end = strchr( start, '\t' ) ) != NULL )
    {
        // %s prints a number of characters, * takes number from stack
        // (your token is not zero-terminated!)
        printf( "%.*s\n", end - start, start );
        start = end + 1;
    }
    // start points to last token, zero-terminated
    printf( "%s", start );
    return 0;
}

نصائح أخرى

استخدم Strtok_R بدلاً من Strtok (إذا كان متاحًا). له استخدام مماثل ، إلا أنه يعود إلى لا تعديل السلسلة مثل Strtok يفعل. [تعديل: في الواقع ، أنا أخطأ. كما يشير كريستوف ، يستبدل Strtok_R المحددات بـ " 0". لذلك ، يجب أن تعمل على نسخة من السلسلة إذا كنت تريد الحفاظ على السلسلة الأصلية. ولكن من الأفضل أن يكون strtok لأنه يعيد إدخال وخيط آمن

ستترك Strtok سلسلتك الأصلية المعدلة. يحل محل المحدد بـ " 0". وإذا صادف أن تكون سلسلةك ثابتة ، مخزنة في ذاكرة قراءة فقط (سيفعل بعض المترجمين ذلك) ، فقد تحصل فعليًا على انتهاك للوصول.

استخدام strtok() من عند string.h.

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

int main ()
{
    char str[] = "test\tbla-bla-bla\t2332";
    char * pch;
    pch = strtok (str," \t");
    while (pch != NULL)
    {
        printf ("%s\n",pch);
        pch = strtok (NULL, " \t");
    }
    return 0;
}

يمكنك استخدام أي مكتبة Regex أو حتى Glib GScanner, ، يرى هنا و هنا للمزيد من المعلومات.

نسخة أخرى ؛ هذا واحد يفصل المنطق إلى وظيفة جديدة

#include <stdio.h>

static _Bool next_token(const char **start, const char **end)
{
    if(!*end) *end = *start;    // first call
    else if(!**end)             // check for terminating zero
        return 0;
    else *start = ++*end;       // skip tab

    // advance to terminating zero or next tab
    while(**end && **end != '\t')
        ++*end;

    return 1;
}

int main(void)
{
    const char *string = "foo\tbar\tbaz";

    const char *start = string;
    const char *end = NULL; // NULL value indicates first call

    while(next_token(&start, &end))
    {
        // print substring [start,end[
        printf("%.*s\n", end - start, start);
    }

    return 0;
}

إذا كنت بحاجة إلى طريقة آمنة ثنائية لتميز سلسلة معينة:

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

void tokenize(const char *str, const char delim, const size_t size)
{
        const char *start = str, *next;
        const char *end = str + size;

        while (start < end) {
                if ((next = memchr(start, delim, end - start)) == NULL) {
                        next = end;
                }

                printf("%.*s\n", next - start, start);
                start = next + 1;
        }
}

int main(void)
{
        char str[] = "test\tbla-bla-bla\t2332";
        int len = strlen(str);

        tokenize(str, '\t', len);

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