Как расположить строку в массиве строк через запятую в c? - PullRequest
0 голосов
/ 24 января 2019

Я пишу C программу, которая будет анализировать разделенную запятыми строку в массивах строк.

Я уже пробовал исходный код, который печатает строку через запятую. Но я хочу, чтобы эти строки были сохранены в массиве строк. Следующий код использует strcspn и использует следующую строку

printf("%.*s\n", (int)field_len, s);

чтобы напечатать строки, которые я не могу понять. Как перенести напечатанную строку в массивы строк?

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

char ArrayOfString[10][5];

void vSeparateSringByComma(char* string)
  {
    const char delims[] = ",";
    const char *s = string;
    int i = 0, j;
    do 
      {
        size_t field_len = strcspn(s, delims);
        printf("%.*s\n", (int)field_len, s);
        s += field_len;
        i++;
      } 

    while (*s++);   
   }

int main() {
    char string[] = "$,0,3,307,183,18,5,119,1,#";
    vSeparateSringByComma(string);
}

Я получаю вывод

$
0
3
307
183
18
5
119
1
#

(после каждой строки есть новая строка) что прекрасно Моя проблема заключается в переносе этих строк в мой массив строк.

Есть предложения?

Ответы [ 3 ]

0 голосов
/ 24 января 2019

Вам нужно решить несколько проблем, чтобы преобразовать вашу функцию от простой печати разделенных строк в stdout до сохранения разделенных строк в ArrayOfString.Прежде чем перейти к изменениям, давайте не будем использовать магические числа в вашем коде.

char ArrayOfString[10][5];

В ArrayOfString выше 10 и 5 являются магическими числами .Это жестко закодированные значения, которые будут регулировать все от размера объявления до необходимых проверок правильности, чтобы защитить границы вашего массива.Вместо значений жесткого кодирования, если вам нужна константа, определите одну (или более), например,

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

#define ROW 10
#define COL  5

char ArrayOfString[ROW][COL];

Теперь разделите вашу строку на токены .Библиотека C предоставляет функцию, специально предназначенную для разделения строк с разделителями на токены.Удобно названный strtok.Единственное предостережение, которое нужно знать о strtok, - это то, что он изменяет строку, поэтому, если вам нужно сохранить оригинал, сначала сделайте копию.

Чтобы использовать strtok (string, delims) для разделения string на токены в delims, ваш первый вызов strtok принимает string в качестве 1-го параметра.Все последующие звонки используют NULL на своем месте.Вы можете либо сделать первоначальный вызов strtok, а затем использовать цикл while для завершения процесса, либо цикл for предназначен для обработки начального вызова, а также всех последующих вызовов с NULL.

Например, ваша функция, использующая strtok для разделения string на токены и обеспечивающая size_t возврат числа токенов, скопированных в ArrayOfString, может быть похожа на:

char ArrayOfString[ROW][COL];

size_t vSeparateSringByComma (char* string)
{
    const char *delims = ",\n";
    char *s = string;
    size_t n = 0, len;

    for (s = strtok (s, delims); s && n < ROW; s = strtok (NULL, delims))
        if ((len = strlen (s)) < COL)
            strcpy (ArrayOfString[n++], s);
        else
            fprintf (stderr, "error: '%s' exceeds COL - 1 chars.\n", s);

    return n;
}

( примечание: как границы вашего массива защищены как проверкой с n < ROW, так и с каждой границей массива строк, защищенной (len = strlen (s)) < COL до копирования в ArrayOfString[n++])

( также обратите внимание: как, если не использовать магические числа , если в будущем вы измените размер ROW или COL, нужно будет изменить только константы, и это изменение будет автоматически включеново всем вашем коде благодаря использованию констант)

Ваш пример программы будет:

int main(void) {

    char string[] = "$,0,3,307,183,18,5,119,1,#";
    size_t n = vSeparateSringByComma (string);

    for (size_t i = 0; i < n; i++)
        printf ("ArrayOfString[%zu] : '%s'\n", i, ArrayOfString[i]);
}

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

$ ./bin/arrayofstrings
ArrayOfString[0] : '$'
ArrayOfString[1] : '0'
ArrayOfString[2] : '3'
ArrayOfString[3] : '307'
ArrayOfString[4] : '183'
ArrayOfString[5] : '18'
ArrayOfString[6] : '5'
ArrayOfString[7] : '119'
ArrayOfString[8] : '1'
ArrayOfString[9] : '#'

Использование strcspn и strspn вместо strtok

Как обсуждалось в комментариях, используйте strcspn, чтобы сообщить количество последовательных символов, не содержащих разделитель, позволяющий вам определять длину каждого поля.Затем вам нужно пропустить разделители (которые во многих случаях могут состоять из нескольких разделителей (например, $, 0, 3, ...).

Хотя strtok считает несколько последовательных разделителей одним разделителем, вам потребуетсяаналогичный способ пропустить промежуточные разделители, чтобы расположить себя для чтения следующего поля. strspn будет работать хорошо, используя тот же delims, но на этот раз сообщая о количестве символов, состоящих только из символов в delims (позволяя вам добавить это к вашим len, а затем len к s, чтобы подготовиться к следующему чтению)

Короткий вариант с использованием strcspn и strspn может быть:

size_t vSeperateSringByComma (char* string)
{
    const char *delims = ",\n";
    char *s = string;
    size_t n = 0, len;

    while ((len = strcspn (s, delims))) {   /* number of non-delim chars */
        if (len < COL) {                    /* validate it will fit */
            memcpy (ArrayOfString[n], s, len);  /* copy len chars */
            ArrayOfString[n++][len] = 0;    /* nul terminate at len */
        }
        else
            fprintf (stderr, "error: '%s' exceeds COL - 1 chars.\n", s);

        len += strspn (s + len, delims);    /* scan past delimiter(s) */
        s += len;               /* update s to beginning of next field */
    }

    return n;
}

(результат тот же)

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

0 голосов
/ 24 января 2019

Я узнал о стандартных функциях strtok() и strcspn(), и я публикую обе версии решения.

Использование strtok ()

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

#define ROW  10
#define COL  30

char ArrayOfString[ROW][COL];

size_t vSeperateSringByComma_New(char* string, char *delims)
{
  char *p;
  p = strtok (string,delims);
  int i = 0,j;
  while (p!= NULL)
  {
    strcpy(ArrayOfString[++i], p);
    p = strtok (NULL, delims);
  }
  return i;
}

int main ()
{
  char string[] ="$,0,3,307,183,18,5,119,1,#";
  char delim[] = ",:";
  printf ("String  \"%s\" is split into tokens:\n",string);
  size_t len = vSeperateSringByComma_New (string, delim);
  int i;
  for (i = 0; i < len+1; i++)   {
    printf ("%s\n",ArrayOfString[i]);
  }
  return 0;
}

Использование strcspn ()

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

#define ROW  10
#define COL  30

char ArrayOfString[ROW][COL];

size_t vSeperateSringByComma(char* string, char *delims)
{
    const char *s = string;
    int i = 0;
    do {
        size_t field_len = strcspn(s, delims);
        sprintf(ArrayOfString[++i],"%.*s", (int)field_len, s);
        s += field_len;
    } while (*s++); 
    return i; 
}

int main() {
    char string[] = "$,0,3,307,183,18,5,119,1,#";
    char delims[] = ",";
    printf ("String  \"%s\" is split into tokens:\n",string);
    int len = vSeperateSringByComma(string, delims);
    int i;
    for (i = 0; i < len+1; i++) {
        printf ("%s\n",ArrayOfString[i]);
    }
}

Спасибо за ваши предложения

0 голосов
/ 24 января 2019

замените

printf("%.*s\n", (int)field_len, s);

на

sprintf(ArrayOfString[i],"%.*s\n", (int)field_len, s);

, затем вы можете напечатать 4 первых элемента с

for( i=0 ; i<4 ; i++)
   printf("%s" , ArrayOfString[i] );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...