маркировка строки в C - PullRequest
2 голосов
/ 28 июля 2010

Привет! Я хочу токенизировать строку в C

Ниже приведена строка.

{Работа запущена} {Работа запущена} {Работа выполнена} {Работа завершена}

Я хочу использовать токены для {и}, чтобы я получил «Задание запущено», «Задание выполнено» и «Завершено задание»

Я также хочу, чтобы в качестве экранированных символов использовался тот же разделитель

{Задание запущено} {Задание \ {ID1 \} Выполнено} {Задание \ {ID2 \} Выполнено} {Задание выполнено}

Должен вернуть мне следующее

Задание начато, задание {ID1}Выполняется, задание {ID2} Выполняется, задание завершено.

У меня есть решение с указателем airthmatic, но я хочу избежать повторного ввода входной строки более одного раза.

Любое предложение.

Ответы [ 9 ]

5 голосов
/ 28 июля 2010

Вы можете использовать простой конечный автомат:

#include <stdio.h>

int main() {
    char *src = "{Job Started}{Job \\{ID1\\} Running}{Job \\{ID2\\} Running}{Job Finished}";

    char token[100] = {}, *dst = token, ch;

    int state = 0;
    while ((ch = *src++) != 0) {
        switch (state) {
            case 0:
                if (ch == '{') state = 1;
                break;
            case 1:
                switch (ch) {
                    case '}':
                        printf("token: %s\n", token);
                        dst = token;
                        *dst = 0;
                        state = 0;
                        break;
                    case '\\':
                        state = 2;
                        break;
                    default:
                        *dst++ = ch;
                        *dst = 0;
                }
                break;
            case 2:
                *dst++ = ch;
                *dst = 0;
                state = 1;
                break;
        }
    }
}
1 голос
/ 28 июля 2010

написать свою собственную функцию для токенизации это должно быть довольно просто, особенно если вы знаете, откуда берется строка (и вам не нужно беспокоиться о странном вводе пользователем, например, {a}{, {{{{{, }a{, {blah} {blah}).

что-то вроде [написано быстро и без проверки !!]:

int tokenize(char* inp, char** outp)
{
    char i = inp;
    int currentToken = 0;

    if(*i == 0)
        return 0;

    outp = (char**)malloc(sizeof(char*) * (strlen(inp) / 2));// allocate a buffer that can hold the maximum # of tokens.
    outp[0] = i;

    while(*i != 0)
    {
        switch(*i)
        {
            case '{':
                // start a new token
                tokenCount = tokenCount + 1;
                outp[currentToken] = i;
                break;
            case '}':
                // skip this character. we assume there is a { coming next.
                break;
            case '\\':
                i = i + 1;
                if(*1 == 0)
                    break;
                // intentional fall-through
            default:
                *outp[currentToken] = *i;
                break;
        }
        if(*i == 0)
            break;
        i = i + 1;
    }

    return currentToken + 1;
}
1 голос
/ 28 июля 2010

Вы можете использовать strtok() с набором разделителей {} (и всем, что вам нужно). Последовательность из двух или более смежных символов-разделителей в анализируемой строке считается одним разделителем, плюс вы можете изменять набор разделителей между последовательными вызовами. Также обратите внимание, что strtok () изменяет данную ему строку.

edit: я понял, что этого недостаточно для твоего второго требования.

0 голосов
/ 28 июля 2010

Если это ваша единственная проблема со сканированием / токенизацией, вам, вероятно, лучше пойти с решением, которое у вас уже есть, или внедрить FSM, как предложено Ферруччо.

Если у вас есть другие подобные проблемы, с другой стороны, выможет искать инструмент или библиотеку, которая может помочь вам в этом.Кто-то предложил lex, но вы также можете настроить библиотеку регулярных выражений.

Учитывая библиотеку соответствия строк, вы можете написать что-то вроде:

pmx_t ret;

ret = pmxMatchStr(src,"&e\\&K{(<*!}>)}&K{(<*!}>)}&K{(<*!}>)}&L")));
if (ret) {
  printf("%.*s, %.*s, %.*s\n",pmxLen(ret,1),pmxStart(ret,1),
                              pmxLen(ret,2),pmxStart(ret,2),
                              pmxLen(ret,3),pmxStart(ret,3)
}

(также обрабатывать пробелы перед или между {...} и съедает конец строки)

Да, пример - бесстыдное продвижение моей библиотеки (pmx) , но та же концепция применима с использованием одного из множества другихВы можете найти googling для регулярных выражений или библиотек регулярных выражений в C.

0 голосов
/ 28 июля 2010

Вы можете использовать sscanf .Вы можете создать соответствующие разделители, используя ссылку в ссылке.

/ * sscanf пример * /

#include <stdio.h>

int main ()
{
  char sentence []="Rudolph is 12 years old";
  char str [20];
  int i;

  sscanf (sentence,"%s %*s %d",str,&i);
  printf ("%s -> %d\n",str,i);

  return 0;
}

Вывод:

Rudolph -> 12

Strtok и strtok_r (повторяемая версия strtok) также могут использоваться для анализа строки.

PS: я копирую свой пример из другого вопроса саналогичные требования

0 голосов
/ 28 июля 2010
char *tokenizer(char *ptr) {
    char *str = ptr;
    char *aux = ptr;

    while (*ptr) {
        if ( *ptr == '\\' && ( *(ptr + 1) == '{' || *(ptr + 1) == '}') ) {
            *aux++ = *(ptr + 1);
            ptr += 2;
        }
        else if ( *ptr == '{') {
            ++ptr;
        }
        else if ( *ptr == '}' ) {
            *aux++ = ( *(++ptr)  != '\0' ) ? ',' : '.';
        }
        else {
            *aux++ = *ptr++;
        }
    }
    *aux = '\0';
    return str;
}
0 голосов
/ 28 июля 2010
char **
split( char **result, char *tmp, const char *src, const char *delim, size_t len)
{
   int i=0;
   char *p=NULL;
   for(i=0; i<len; i++) 
      result[i]=NULL;
   if(!*src)
      return result;
   strcpy(tmp, src);
   for(i=0, p=strtok(tmp, delim); p!=NULL; p=strtok(NULL, delim), i++ )
   {
      result[i]=p;
   }
   return result;
}

Этот пример не уничтожает исходную строку, вы передаете рабочую строку.

0 голосов
/ 28 июля 2010

Если вы хотите расширить его функциональность, вы можете взглянуть на Eric Robert's scannerADT. Его очень просто использовать, и вы можете добавить к нему метод setDelimiter.

Здесь - это .c и .h для него.

0 голосов
/ 28 июля 2010

Я использовал strtok () для этого.Это не работает для строк с экранированными символами, но я думаю, что это можно изменить, чтобы понять их.Это не так тривиально, хотя.Надеюсь, это поможет вам.

#include <stdio.h>
#include <string.h>
int main(void) {
    char str[] = "{Job Started}{Job Running}{Job Running}{Job Finished}";
    char* pch;
    pch = strtok(str,"{}");
    while(pch!=NULL) {
        printf("%s\n",pch);
        pch = strtok(NULL,"{}");
    }
    return 0;
}

У Делнана есть смысл.Манипулирование строками слишком сложно и уязвимо для ошибок обработки указателей в C. Если C не является обязательным для вашего проекта, вам определенно следует использовать какой-то другой язык.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...