Я пытался разметить строку, используя ПРОБЕЛ в качестве разделителя, но это не сработало. Есть ли у кого-нибудь предложения о том, почему это не работает?
Обновлено: токенизация с использованием:
strtok(string, " ");
Код выглядит следующим образом
pch = strtok (str," ");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ");
}
В ПОРЯДКЕ. Теперь мы кое-что получим. Какого поведения вы ожидаете, чего не получаете?
Ваш код правильный, сообщите нам, какова ваша строка ввода и результат.
Кстати, комбо. Многие люди, которые работают в справочных службах или преподают, видят фразу «это не работает» как обозначение пользователя, который не читал предоставленное руководство, или не знает, чего он на самом деле хочет, или глубоко сбит с толку. Вам нужна форма: «Я делаю X, и я ожидал Y, но у меня Z. Что не так?»
@dmckee: хороший момент. Каноническая ссылка на x-ref: catb.org/~esr/faqs/smart-questions.html
Вы используете strtok или что-то, что вырастили сами? cplusplus.com/reference/clibrary/cstring/strtok.html Если вы используете strtok, вы пытаетесь сделать это с постоянной строкой?





Читая документацию по strtok, я вижу, что вам нужно передать NULL-указатель после первого "инициализирующего" вызова. Может, ты этого не делал. Только предположение, конечно.
Делай это так:
char s[256];
strcpy(s, "one two three");
char* token = strtok(s, " ");
while (token) {
printf("token: %s\n", token);
token = strtok(NULL, " ");
}
Примечание. strtok модифицирует строку, в которой используется токенизация, поэтому это не может быть const char*.
Вот пример использования strtok, имейте в виду, что strtok разрушает свою входную строку (и, следовательно, не может использоваться Когда-либо для строковой константы
char *p = strtok(str, " ");
while(p != NULL) {
printf("%s\n", p);
p = strtok(NULL, " ");
}
В основном следует отметить, что передача NULL в качестве первого параметра в strtok указывает ему получить следующий токен из строки, которую он ранее токенизировал.
Как strtok() узнает, когда получить следующий токен из строки, которую он ранее токенизировал? Мне кажется, что strtok() должен токенизировать значение NULL. Я ожидал ошибки.
strtok имеет внутреннюю переменную состояния, отслеживающую токенизируемую строку. Когда вы передадите ему NULL, strtok продолжит использовать эту переменную состояния. Когда вы передаете ненулевое значение, переменная состояния сбрасывается. Другими словами: передача NULL означает «продолжить токенизацию той же строки».
Спасибо за разъяснения. Но в любом случае это кажется ужасным дизайном.
вы правы, поэтому многие реализации предлагают strtok_r, которые в наименьшей степени предлагают способ его использования в потокобезопасном режиме.
Разве char *p не следует сначала выделить немного места? На что указывает указатель, возвращаемый strtok? Просто случайное место в памяти? О ... указывает ли это на место в данной строке?
@Gnuey, p будет указывать на символы в токенизируемой строки. Кроме того, strtok заменяет найденный разделитель на символ '\0', так что p фактически будет действительной строкой с завершением NUL. Итак, если бы вы запускали его на char[] s = "hello world";, первый вызов вернул бы указатель на символ h, и тогда буфер содержал бы "hello\0world".
Как можно сохранить это значение «p» в массиве для сравнения ??????????? положение в положение
@delive, я не уверен, что вы на самом деле спрашиваете (и несколько "?" не улучшают читаемость). Я рекомендую написать новый вопрос, чтобы сообщество попыталось ответить.
Да, например, дата: это дата 19/09/2016, с разделением можно получить 19/09/2016, теперь я хочу поместить значение по значению в массив ints [] = {1,9,0,9,2,0 , 1,6} Я знаю, что [0] и [1] == день, вы меня понимаете? и вы можете сравнивать дни, месяцы и годы с массивом из 8 позиций
@delive, я думаю, что понимаю вас, но комментарии - это нет место для вопросов и ответов, поэтому, пожалуйста, создайте новый вопрос, и сообщество ответит как можно лучше.
Вы можете упростить код, добавив дополнительную переменную.
#include <string.h>
#include <stdio.h>
int main()
{
char str[100], *s = str, *t = NULL;
strcpy(str, "a space delimited string");
while ((t = strtok(s, " ")) != NULL) {
s = NULL;
printf(":%s:\n", t);
}
return 0;
}
strtok может быть очень опасным. Это не потокобезопасный. Его предполагаемое использование должно вызываться снова и снова в цикле, передавая результат предыдущего вызова. Функция strtok имеет внутреннюю переменную, в которой хранится состояние вызова strtok. Это состояние не уникально для каждого потока - оно глобально. Если какой-либо другой код использует strtok в другом потоке, у вас возникнут проблемы. Не из тех проблем, которые вы хотите отследить!
Я бы рекомендовал поискать реализацию регулярного выражения или использовать sscanf для разделения строки.
Попробуй это:
char strprint[256];
char text[256];
strcpy(text, "My string to test");
while ( sscanf( text, "%s %s", strprint, text) > 0 ) {
printf("token: %s\n", strprint);
}
Примечание. Текстовая строка уничтожается по мере разделения. Это не может быть предпочтительным поведением =)
Фактически, если вы посмотрите на современные реализации strtok, они, как правило, используют локальное хранилище потоков (MSVC, безусловно, делал это в течение многих лет), поэтому они являются потокобезопасными. Это все еще архаичная функция, которой я бы избегал ...
strtok_r - это поточно-ориентированная версия strtok pubs.opengroup.org/onlinepubs/009695399/functions/strtok.htm l
Я согласен с первым абзацем, но предложение после него ужасное. scanf трудно использовать должным образом, как показано в вашем примере; вы забыли передать размер (%255s).
Я сделал несколько строковых функций для разделения значений, используя как можно меньше указателей, потому что этот код предназначен для работы на процессорах PIC18F. Эти процессоры не очень хорошо справляются с указателями, когда у вас мало свободной оперативной памяти:
#include <stdio.h>
#include <string.h>
char POSTREQ[255] = "pwd=123456&apply=Apply&d1=88&d2=100&pwr=1&mpx=Internal&stmo=Stereo&proc=Processor&cmp=Compressor&ip1=192&ip2=168&ip3=10&ip4=131&gw1=192&gw2=168&gw3=10&gw4=192&pt=80&lic=&A=A";
int findchar(char *string, int Start, char C) {
while((string[Start] != 0)) { Start++; if (string[Start] == C) return Start; }
return -1;
}
int findcharn(char *string, int Times, char C) {
int i = 0, pos = 0, fnd = 0;
while(i < Times) {
fnd = findchar(string, pos, C);
if (fnd < 0) return -1;
if (fnd > 0) pos = fnd;
i++;
}
return fnd;
}
void mid(char *in, char *out, int start, int end) {
int i = 0;
int size = end - start;
for(i = 0; i < size; i++){
out[i] = in[start + i + 1];
}
out[size] = 0;
}
void getvalue(char *out, int index) {
mid(POSTREQ, out, findcharn(POSTREQ, index, '='), (findcharn(POSTREQ, index, '&') - 1));
}
void main() {
char n_pwd[7];
char n_d1[7];
getvalue(n_d1, 1);
printf("Value: %s\n", n_d1);
}
int not_in_delimiter(char c, char *delim){
while(*delim != '\0'){
if (c == *delim) return 0;
delim++;
}
return 1;
}
char *token_separater(char *source, char *delimiter, char **last){
char *begin, *next_token;
char *sbegin;
/*Get the start of the token */
if (source)
begin = source;
else
begin = *last;
sbegin = begin;
/*Scan through the string till we find character in delimiter. */
while(*begin != '\0' && not_in_delimiter(*begin, delimiter)){
begin++;
}
/* Check if we have reached at of the string */
if (*begin == '\0') {
/* We dont need to come further, hence return NULL*/
*last = NULL;
return sbegin;
}
/* Scan the string till we find a character which is not in delimiter */
next_token = begin;
while(next_token != '\0' && !not_in_delimiter(*next_token, delimiter)) {
next_token++;
}
/* If we have not reached at the end of the string */
if (*next_token != '\0'){
*last = next_token--;
*next_token = '\0';
return sbegin;
}
}
void main(){
char string[10] = "abcb_dccc";
char delim[10] = "_";
char *token = NULL;
char *last = "" ;
token = token_separater(string, delim, &last);
printf("%s\n", token);
while(last){
token = token_separater(NULL, delim, &last);
printf("%s\n", token);
}
}
Подробный анализ вы можете прочитать в блоге, упомянутом в моем профиле :)
Хорошо, @jitsceait, но что произойдет, если у меня на входе будет два разделителя? Немного изменю твой код.
Я думаю, что добавил тестовый пример для последовательных разделителей, и он работал. Не могли бы вы выделить код, который вы изменили?
Вот еще одна реализация strtok(), которая может распознавать последовательные разделители (в стандартной библиотеке strtok() этого нет)
Функция является частью лицензированной строковой библиотеки BSD и называется zString. Приглашаем вас внести свой вклад :)
https://github.com/fnoyanisi/zString
char *zstring_strtok(char *str, const char *delim) {
static char *static_str=0; /* var to store last address */
int index=0, strlength=0; /* integers for indexes */
int found = 0; /* check if delim is found */
/* delimiter cannot be NULL
* if no more char left, return NULL as well
*/
if (delim==0 || (str == 0 && static_str == 0))
return 0;
if (str == 0)
str = static_str;
/* get length of string */
while(str[strlength])
strlength++;
/* find the first occurance of delim */
for (index=0;index<strlength;index++)
if (str[index]==delim[0]) {
found=1;
break;
}
/* if delim is not contained in str, return str */
if (!found) {
static_str = 0;
return str;
}
/* check for consecutive delimiters
*if first char is delim, return delim
*/
if (str[0]==delim[0]) {
static_str = (str + 1);
return (char *)delim;
}
/* terminate the string
* this assignmetn requires char[], so str has to
* be char[] rather than *char
*/
str[index] = '\0';
/* save the rest of the string */
if ((str + index + 1)!=0)
static_str = (str + index + 1);
else
static_str = 0;
return str;
}
Как упоминалось в предыдущих сообщениях, поскольку strtok() или тот, который я использовал выше, полагается на переменную static *char для сохранения положения последнего разделителя между последовательными вызовами, следует проявлять особую осторожность при работе с многопоточными приложениями.
ваш пример получит первый токен, посмотрите ответы gbjbaanb или мои для правильного использования.