2013-09-16 2 views
5

У меня есть файл CSV, содержащий данные, такие какПолучение нулевой длины строки из strtok()

value;name;test;etc 

, который я пытаюсь разделить с помощью strtok(string, ";"). Однако, этот файл может содержать данные нулевой длины, например:

value;;test;etc 

какие strtok() пропуски. Есть ли способ избежать strtok, пропуская данные нулевой длины?

+0

Является ли 'strsep()' доступным на вашей платформе? Использование очень похоже на 'strtok()', но оно корректно возвращает пустые поля. –

+0

@MartinR вероятно. Я использую Fedora w/Linux 3.10.10. – Mauren

+1

Так что это может быть альтернатива. Но даже это не будет обрабатывать разделители внутри цитируемого текста, например 'aaa; bbb;" ddd; eee "; fff' правильно. –

ответ

5

Возможной альтернативой является использование функции BSD strsep() вместо strtok(), если таковая имеется. Из man page:

strsep() функция предназначена в качестве замены для функции strtok() .В то время как функция strtok() должна быть предпочтительной для целей мобильности (она соответствует ISO/IEC 9899: 1990 («ISO C90»)) не может обрабатывать пустые поля, то есть обнаруживать поля, разделенные двумя смежными разделительными символами, или который будет использоваться более чем за одну строку за один раз: . Функция strsep() впервые появилась в 4.4BSD.

Простой пример (также скопирован с этой страницы человека):

char *token, *string, *tofree; 

tofree = string = strdup("value;;test;etc"); 
while ((token = strsep(&string, ";")) != NULL) 
    printf("token=%s\n", token); 

free(tofree); 

Выход:

 
token=value 
token= 
token=test 
token=etc 

так пустые поля обрабатываются корректно.

Конечно, как другие уже говорил, ни один из этих простых функций Tokenizer не обрабатывает разделителя внутри кавычек правильно, так что если это вопрос, вы должны использовать в надлежащего CSV разбор библиотеки.

+0

Работала как шарм. Большое спасибо! – Mauren

3

Невозможно сделать strtok() не так. От man page:

Последовательность из двух или более смежных разделителей байт в разобранных строке считается один разделителем. Байты-разделители в начале или конце строки игнорируются. Иными словами: токены , возвращенные strtok(), всегда являются непустыми строками.

Но что вы можете сделать, это проверить количество '\0' символов перед маркером, поскольку strtok() заменяет все встретившиеся маркеры с '\0'. Таким образом, вы узнаете, сколько токенов было пропущено. Source info:

Этот конец маркера автоматически заменяется на нуль-символа, и начало лексемы возвращается функцией.

И образец кода, чтобы показать, что я имею в виду.

char* aStr = ...; 
char* ptr = NULL; 

ptr = strtok (...); 

char* back = ptr; 
int count = -1; 
do { 
    back--; 
    if (back <= aStr) break; // to protect against reads before aStr 
    count++; 
} while (*back = '\0'); 

(написанный без идеи или тестирования, может быть недействительной реализации, но идея стоит).

+0

Звучит честно. Я попробую этот подход. – Mauren

+1

Буду благодарен за комментарии о downvotes, я бы хотел исправить эту реализацию, если с ней что-то не так. – Dariusz

2

Нет, вы не можете. От «человек strtok»:

последовательность из двух или более смежных символов разделителей в анализируемой строке считается один разделитель. Разделитель символов в начале или конце строки игнорируются. Поместите другим способом: жетоны, возвращаемые strtok(), всегда непустые строки.

Вы также можете столкнуться с проблемами, если ваши данные содержат разделитель внутри кавычек или любой другой «побег».

Я думаю, что лучшим решением является получение библиотеки синтаксического анализа CSV или создание собственной функции синтаксического анализа.

+0

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

+1

Ну, избегая этого, на самом деле это хорошая идея. Существует эта библиотека, которая рекомендуется в другом потоке StackOverflow: http://sourceforge.net/projects/libcsv/ –

Смежные вопросы