Можно ли использовать функцию strtok только на непересекающихся строках? - PullRequest
0 голосов
/ 19 декабря 2018

В приведенном ниже коде есть два экземпляра подстроки «on» в строковых данных.Но возможно ли применить strtok только к подстроке «on», которая не перекрывается (то есть не является частью другого слова)?Если да, может кто-нибудь сказать мне, как и что я делаю неправильно в коде ниже?

#include<stdio.h>
#include<string.h>
#include<ctype.h>

int main()
{  
  char data[50]="Jason could you please turn on the TV";
  char delimiter[5]="on";

  char *ptr,*pointer,*pa,*p,*pb[10];
  int i=0,j=0,k=0,count=0;

  p=data;
  pointer=data;

  while((*pointer!='\0')&&(pointer=strstr(pointer,delimiter)))
  {
    pa=pointer+strlen(delimiter);
    ptr=(--pointer);

    while((isspace(*ptr))&&(isspace(*pa)))
    {
      pb[count]=strtok(ptr,delimiter);
      printf("%s\n",pb[count]);
      count++;
      break;

     } 

      pointer++;
     (*pointer)++;

  }   


}

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

Не совсем понятно из вашего использования «неперекрывающихся», каково ваше намерение с data, но я беру это из ваших дополнительных комментариев, которые вы хотите найти "on" в data как целое словоа не "on" как часть "Jason".

При попытке найти "on" в пределах data вам не нужен strtok, strspn или strcspn, правильный инструмент для работыравен strstr, что позволяет найти первое вхождение подстроки в строке.Ваша единственная работа заключается в определении правильной подстроки для поиска.

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

Во-первых,связанных с вашей инициализацией data, если вы не собираетесь добавлять свою строку в свой код, нет необходимости указывать magic-number 50, просто оставьте [] пустым и data будет иметь соответствующий размер для хранения строки, например,

    char data[]="Jason could you please turn on the TV",
        *p = data;    /* pointer to data */

Аналогично, если вы не планируете изменить свой разделитель, вы можете просто использовать string-literal , например

    const char *delim = " on";

Затем, чтобы найти " on" в данных, все, что вам нужно, это один вызов strstr (p, delim), и вы можете сделать вызов в условном выражении, чтобы определить, существует ли он, например,

    if ((p = strstr (p, delim))) {
        size_t len = strlen (delim);
        char *next = p + len;
        if (isspace (*next) || ispunct (*next)) {
            printf ("found: '%s' (now what?)\n", ++p);
        }
    }

Если он найден, просто объявите указатель (или используйте индексирование массива с помощью p), чтобы получить доступ к следующему символу после " on".Затем вы можете проверить, является ли то, что следует " on", пробелом, который подтверждает, что вы нашли нужную подстроку.Поскольку вы знаете, p указывает на space до "on", вы можете просто увеличить указатель p, чтобы он указывал на "on", как это было сделано выше в инструкции printf.Теперь то, что вы делаете с остальной частью строки, зависит от вас.У вас есть p, указывающий на начало строки, и next, указывающий на пробел после "on", так что вы можете тривиально скопировать "on" или nul-terminate в next -все, что вам нужно сделать.

Если сложить все вместе, вы получите:

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main (void) {

    char data[]="Jason could you please turn on the TV",
        *p = data;
    const char *delim = " on";

    if ((p = strstr (p, delim))) {
        size_t len = strlen (delim);
        char *next = p + len;
        if (isspace (*next) || ispunct (*next)) {
            printf ("found: '%s' (now what?)\n", ++p);
        }
    }

    return 0;
}

Пример использования / Вывод

$ ./bin/strstr_on
found: 'on the TV' (now what?)

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

Поиск нескольких "on" В строке

Как объяснено в комментариях ниже, если у вас есть несколько "on" находится на вашем входе, все, что вам нужно сделать, это поместить приведенный выше оператор if в цикл, а затем установить p = next; в конце цикла.Например, единственные изменения, необходимые для поиска всех подстрок, начинающихся с "on", можно сделать следующим образом:

    char data[]="Jason could you please turn on the TV on the desk",
    ...
    while ((p = strstr (p, delim))) {
        size_t len = strlen (delim);
        char *next = p + len;
        if (isspace (*next) || ispunct (*next)) {
            printf ("found: '%s' (now what?)\n", ++p);
        }
        p = next;
    }

Использовать / выводить Поиск всех "on"

$ ./bin/strstr_on
found: 'on the TV on the desk' (now what?)
found: 'on the desk' (now what?)

Дайте мне знать, если у вас есть еще вопросы.

0 голосов
/ 19 декабря 2018

strspn и strcspn могут использоваться для анализа строки на предмет соответствия слова.
strtok будет разбивать строку при каждом появлении отдельных символов в разделителе.Это не очень подходит для того, что вы, кажется, хотите сделать.

#include <stdio.h>
#include <string.h>

int main() {
    char data[50]="Jason could you please turn on the TV";
    char delimiter[5]="on";
    char *parse = data;
    size_t space = 0;
    size_t span = 0;

    while ( *parse){//parse not pointing to zero terminator
        space = strspn ( parse, " \n\t");//leading whitespace
        parse += space;//advance past whitespace
        span = strcspn ( parse, " \n\t");//not whitespace
        if ( span) {
            printf("word is: %.*s\n", (int)span, parse);//prints span number of characters
        }
        if ( 0 == strncmp ( delimiter, parse, span)) {
            printf ( "\tword matches delimiter: %s\n", delimiter);//found match
        }
        parse += span;//advance past non whitespace for next word
    }
    return 0;
}

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

#include <stdio.h>
#include <string.h>

int main() {
    char data[50]="Jason could you please turn on the TV";
    char delimiter[5]="on";
    char *parse = data;
    size_t space = 0;
    size_t span = 0;

    while ( *parse){//parse not pointing to zero terminator
        space = strspn ( parse, " \n\t");//leading whitespace
        parse += space;//advance past whitespace
        span = strcspn ( parse, " \n\t");//not whitespace
        if ( span) {
            printf("word is: %.*s\n", (int)span, parse);//prints span number of characters
            if ( 0 == strncmp ( delimiter, parse, span)) {
                printf ( "\tword matches delimiter: %s\n", delimiter);//found match
                *parse = 0;
                parse += span;
                space = strspn ( parse, " \n\t");//leading whitespace
                parse += space;
                break;
            }
        }
        parse += span;//advance past non whitespace for next word
    }
    printf ( "\n\nsplit strings:\n%s\n%s\n", data, parse);
    return 0;
}

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

#include <stdio.h>
#include <string.h>

char *strwordsep ( char *str, char *word, size_t *stop) {
    char *parse = str;
    size_t space = 0;
    size_t span = 0;

    while ( *parse){//parse not pointing to zero terminator
        space = strspn ( parse, " \n\t");//leading whitespace
        parse += space;//advance past whitespace
        span = strcspn ( parse, " \n\t");//not whitespace
        if ( span) {
            // printf("word is: %.*s\n", (int)span, parse);//prints span number of characters
            if ( 0 == strncmp ( word, parse, span)) {
                // printf ( "\tword matches delimiter: %s\n", word);//found match
                // *parse = 0;//zero terminate
                *stop = parse - str;
                parse += span;//advance past delimiter
                space = strspn ( parse, " \n\t");//leading whitespace
                parse += space;//advance past whiteespace
                return parse;
            }
        }
        parse += span;//advance past non whitespace for next word
    }
    return NULL;
}

int main() {
    char data[]="Jason, I am on the phone, could you please turn on the TV";
    char word[5]="on";
    char *lead = data;
    char *trail = data;
    size_t stop = 0;
    while ( ( trail = strwordsep ( lead, word, &stop))) {
        printf ( "\nsplit strings:\n%.*s\n", (int)stop, lead);
        lead = trail;
    }
    if ( *lead) {
        printf ( "\nsplit strings:\n%s\n", lead);
    }
    return 0;
}

Редактировать

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *strwordsep ( char *str, char *word, size_t *stop) {
    char *parse = str;
    size_t space = 0;
    size_t span = 0;

    while ( *parse){//parse not pointing to zero terminator
        space = strspn ( parse, " \n\t");//leading whitespace
        parse += space;//advance past whitespace
        span = strcspn ( parse, " \n\t");//not whitespace
        if ( span) {
            // printf("word is: %.*s\n", (int)span, parse);//prints span number of characters
            if ( 0 == strncmp ( word, parse, span)) {
                // printf ( "\tword matches delimiter: %s\n", word);//found match
                // *parse = 0;//zero terminate
                *stop = parse - str;
                parse += span;//advance past delimiter
                space = strspn ( parse, " \n\t");//leading whitespace
                parse += space;//advance past whiteespace
                return parse;
            }
        }
        parse += span;//advance past non whitespace for next word
    }
    return NULL;
}

char **freelines ( char **ppc) {
    int each = 0;
    while ( ppc[each]) {//loop until sentinel NULL
        free ( ppc[each]);//free memory
        each++;
    }
    free ( ppc);//free pointers
    return NULL;
}

char **addline ( char **ppc, int *lines, char *add, int length) {
    char **temp = NULL;
    if ( ( temp = realloc ( ppc, sizeof ( *temp) * ( *lines + 2)))) {//add pointer
        ppc = temp;//assign reallocated pointer to original
        if ( ( ppc[*lines] = malloc ( length + 1))) {//allocate memory to pointer
            strncpy ( ppc[*lines], add, length);//copy lenght characters to pointer
            ppc[*lines][length] = 0;
        }
        else {
            fprintf ( stderr, "problem malloc\n");
            ppc = freelines ( ppc);//release memory
            return ppc;
        }
        ppc[*lines + 1] = NULL;//sentinel NULL
        *lines = *lines + 1;
    }
    else {
        fprintf ( stderr, "problem realloc\n");
        ppc = freelines ( ppc);//release memory
        return ppc;
    }
    return ppc;
}

void showlines ( char **ppc) {
    int each = 0;
    while ( ppc[each]) {
        printf ( "output[%d]= %s\n", each, ppc[each]);
        each++;
    }
}

int main() {
    char data[]="Jason, I am on the phone, could you please turn on the TV";
    char word[5]="on";
    char **output = NULL;//pointer to pointer to store sub-strings
    char *lead = data;
    char *trail = data;
    int lines = 0;
    size_t stop = 0;
    while ( ( trail = strwordsep ( lead, word, &stop))) {
        if ( ! ( output = addline ( output, &lines, lead, (int)stop))) {
            return 0;
        }
        lead = trail;
    }
    if ( *lead) {
        if ( ! ( output = addline ( output, &lines, lead, (int)strlen ( lead)))) {
            return 0;
        }
    }
    showlines ( output);
    output = freelines ( output);
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...