Как безопасно разобрать строку с разделителями табуляции? - PullRequest
0 голосов
/ 01 октября 2010

Как правильно разобрать строку табуляции-разделителя? например: test \ tbla-bla-bla \ t2332?

Ответы [ 6 ]

5 голосов
/ 01 октября 2010

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;
}
4 голосов
/ 01 октября 2010

Используйте strtok_r вместо strtok (если он доступен). Он имеет аналогичное использование, за исключением того, что он является реентерабельным, и он не изменяет строку, как strtok. [ Редактировать: На самом деле, я ошибся. Как указывает Кристоф, strtok_r заменяет разделители на «\ 0». Итак, вы должны работать с копией строки, если вы хотите сохранить исходную строку. Но он предпочтительнее strtok, потому что он реентерабелен и безопасен для потоков]

strtok оставит вашу исходную строку измененной. Он заменяет разделитель на «\ 0». И если ваша строка окажется константой, хранящейся в постоянной памяти (некоторые компиляторы это сделают), вы можете получить нарушение прав доступа.

2 голосов
/ 01 октября 2010

Использование 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;
}
0 голосов
/ 12 апреля 2013

Если вам нужен бинарный безопасный способ токенизации заданной строки:

#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;
}
0 голосов
/ 01 октября 2010

Еще одна версия;эта разделяет логику в новую функцию

#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;
}
0 голосов
/ 01 октября 2010

Вы можете использовать любую библиотеку регулярных выражений или даже GLib GScanner, см. здесь и здесь для получения дополнительной информации.

...