Разбирать слова с помощью strtok

Я хочу сказать strtok() использовать в качестве разделителей все, кроме буквенно-цифровых символов.

Мои попытки приведены на примере ref:

/* strtok example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

Однако я собираюсь анализировать настоящие текстовые файлы (содержащие отзывы о сайте). В настоящее время я проверяю, какие другие разделители встречаются, и увеличиваю второй аргумент strtok(). Например, я увидел [, поэтому я сделал это " ,.-[" и так далее, но ладно, я мог что-то упустить, и, возможно, новый текстовый файл содержит новый разделитель.

Неужели нельзя сделать что-то поумнее (и собственно правильное, ибо этого нет)?

Например, если я получу:

[Hello_sir I'm George]

Я хотел бы получить эти токены:

Hello
sir
I
m
George

Проблема в том, что я не знаю, какие разделители.

Я бы хотел использовать в качестве разделителей все, кроме буквенно-цифровых символов.


РЕДАКТИРОВАТЬ

Я подумал о том, чтобы пройти посимвольно и проверить, является ли он буквенно-цифровым, но я надеялся на что-то встроенное, например, на подачу по желанию strtok().


person gsamaras    schedule 11.11.2014    source источник
comment
может быть, вы можете просто использовать isalpha char за char? cplusplus.com/reference/cctype/isalpha   -  person user2485710    schedule 12.11.2014
comment
О да, я тоже об этом думал, позвольте мне обновить @user2485710   -  person gsamaras    schedule 12.11.2014
comment
stackoverflow.com/a/26243667/971127 Сделать, потому что нет.   -  person BLUEPIXY    schedule 12.11.2014
comment
@BLUEPIXY, мне тоже нужно сохранить цифры, стесняюсь, я сказал буквенно-цифровой. Как вы думаете, если я передам в качестве второго аргумента вашей функции isalnum(), все будет в порядке?   -  person gsamaras    schedule 12.11.2014
comment
@ Г. Самарас, все будет хорошо.   -  person BLUEPIXY    schedule 12.11.2014
comment
Подтверждено @BLUEPIXY. Тогда я не понимаю, почему мой вопрос имеет смысл существования.   -  person gsamaras    schedule 12.11.2014


Ответы (2)


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

static char delims[256]; /* this is oversized */

...

void
initdelims()
{
    int i;
    int j = 0;
    for (i = 1; i<256; i++)
    {
        if (!isalnum(i))
            delims[j++] = i;
    }
    delims[j] = 0; /* this is unnecessary as statics are initialised to zero */
}

Затем используйте delims в качестве строки-разделителя.

Однако это и некрасиво, и неэффективно. Вам лучше написать парсер, свернутый вручную, позаимствовав отправить на strtok, если это необходимо.

person abligh    schedule 11.11.2014
comment
Это именно то, о чем я думал. Однако из соображений переносимости вы должны использовать 1 << CHAR_BIT вместо 256. Кроме того, почему это было бы неэффективно - я не уверен, что это вообще имеет значение. Скорее всего, нет. - person The Paramagnetic Croissant; 12.11.2014
comment
strtok будет для каждого символа перебирать 200 с лишним символов строки разделителя. isalpha IIRC просматривает фиксированное растровое изображение. Таким образом, strtok с разделителем из 200 с лишним символов, скорее всего, будет в 200 раз медленнее, чем что-то, свернутое вручную, что не очень весело. - person abligh; 12.11.2014
comment
Это не сработает, я только что проверил. Однако в комментариях к вопросу я получил пользовательскую реализацию, которая делает именно то, что я хочу, поэтому я подумал, что нам, возможно, следует удалить мой вопрос (что можно сделать, только если вы удалите свой ответ). - person gsamaras; 12.11.2014
comment
Я думаю, проблема заключалась в том, что i=0 не является буквенно-цифровым, поэтому delims пусто. Исправил это в исходниках. Предложите другим (хотя бы потому, что они узнают, что перекатывание рук более полезно) - person abligh; 12.11.2014

Вы можете собрать небуквенно-цифровые символы один раз, за ​​один проход, в одну строку, а затем использовать эту строку в качестве разделителя, установленного для strtok():

char delims[(1 << CHAR_BIT) + 1] = { 0 };
for (int i = 0, j = 0; i < sizeof delims - 1; i++) {
    if (!isalnum(i)) {
        delims[j++] = i;
    }
}

pch = strtok(str, delims);
while (pch != NULL)
{
    printf ("%s\n",pch);
    pch = strtok(NULL, delims);
}
person The Paramagnetic Croissant    schedule 11.11.2014
comment
Хороший улов при использовании isalnum(), но обратите внимание на CHAR_BIT: stackoverflow.com/questions/19708810/. Я использовал 256+1, и код не работал. - person gsamaras; 12.11.2014
comment
Я использовал 256+1, и код не работал, я только что проверил. Однако в комментариях к вопросу я получил пользовательскую реализацию, которая делает именно то, что я хочу, поэтому я подумал, что нам, возможно, следует удалить мой вопрос (что можно сделать, только если вы удалите свой ответ). - person gsamaras; 12.11.2014