Разделяйте имя, отчество и фамилию с помощью strtok_r. - PullRequest
0 голосов
/ 17 октября 2019

Так что у меня возникли некоторые проблемы, связанные с моим предыдущим квестом в программировании на СиНа этот раз о том, как отделить имена от файла /etc/passwd, используя strtok_r или strtok. Дело в том, что я хочу разделить имена пользователей на две части: имя и отчество (при условии, что они получили одну) в первой и фамилию во второй. Но я не могу найти способ правильно разделить имена. Я заставил его работать с их именем в первой части, но затем отчество присоединяется к фамилии.

Строки /etc/passwd выглядят так:

s214907:x:1240:1251:Jonas Villa,,,:/home/s214907:/bin/bash
s212167:x:1297:1306:Konstantina Pavlova Rusenkova,,,:/home/s212167:/bin/bash

Пример того, что я получаю:

[Konstantina] [Pavlova Ruskenova] 

Пример того, как я хочу его напечатать:

[Konstantina Pavlova] [Ruskenova]

Пока это мой код:

          char line[256], words[20];
          char *mname, *tmp, *uid, *sp, *lname, *uname, *name, *fname, *tmps;
          int bindex=0, index, cnt =0, count;
          char *rest = NULL;
          FILE*fp = fopen("/etc/passwd","r");
          size_t len = 0;
          char *next = NULL;
          while(fgets(line,256,fp)!=NULL)
          {
                  sp       = strtok(line, ":");
                  tmp      = strtok(NULL, ":");
                  uid      = strtok(NULL, ":");
                  tmp      = strtok(NULL, ":");
                  name     = strtok(NULL, ":,");




                  if(atoi(uid) > 999)
                  {
                          for(tmps = strtok_r(name, " ", &rest);
                                  tmps != NULL;
                                  tmps = strtok_r(NULL, ",", &rest)) {
                                  tmps = strtok(tmps, ",");
                                  printf("[%s]\n", tmps);
                          }
                  }
                  cnt++;
          }
          fclose(fp);

1 Ответ

0 голосов
/ 17 октября 2019

Ваш подход к использованию strtok_r или strtok для разделения имен не работает.

После того, как вы токенизируете (полное) имя, вы получите следующее:

name="Konstantina Pavlova Rusenkova"

Выполучить это имя по name = strtok(NULL, ":,");. Поэтому он не может содержать никаких ','. Если бы был ',', то строка была бы там разрезана.

Любая дальнейшая токенизация с использованием разделителя ',' не может получить никакого полезного результата, кроме как вернуть саму полную строку.

Это означает, что во внутреннем цикле tmps = strtok(tmps, ","); ничего не будет делать.

Я добавил несколько отпечатков:

printf("name=%s\n",name);

    if(atoi(uid) > 999)
    {
        for(tmps = strtok_r(name, " ", &rest);
            tmps != NULL;
            tmps = strtok_r(NULL, ",", &rest))
        {
            printf("tmps:%s\n", tmps); 
            tmps = strtok(tmps, ",");
            printf("  [%s]\n", tmps);
        }
    }

Результат:

name=Konstantina Pavlova Rusenkova
tmps:Konstantina
  [Konstantina]
tmps:Pavlova Rusenkova
  [Pavlova Rusenkova]

Второй отпечаток показывает, что вы вводите в tmps=strtok(tmps,",");. Как упомянуто выше, разделитель никогда не присутствует, оставляя все во вторых скобках.

Как правило, strtok и friends бесполезны для разделения имени. Если разделить строки, не оставляя двух имен вместе. Пробел заменяется на \0.

Вместо этого вы можете просто найти последний пробел и разбить его там:

    if(atoi(uid) > 999)
    {
        char *first = name;
        char *last = strrchr(name,' ');

        if (last != NULL)
        {
            *last = 0;
            last++;

            printf("[%s] [%s]\n", first, last);
        }
    }

Это даст

name=Konstantina Pavlova Rusenkova
[Konstantina Pavlova] [Rusenkova]

Itтакже по-прежнему работает с именами только с одним именем:

name=James Kirk
[James] [Kirk]

Если имеется всего одно имя, вам нужно немного адаптировать.

Примечание:

Еслипо какой-то причине вы настаиваете на использовании strtok также для разделения имени, вам необходимо использовать разделитель ' ', а затем склеить первую и вторую подстроку.

Это будет выглядеть так:

    if(atoi(uid) > 999)
    {
        for(tmps = strtok_r(name, " ", &rest);
            tmps != NULL;
            tmps = strtok_r(NULL, " ", &rest))
            {
                printf("tmps:%s\n", tmps);
                printf("  [%s]\n", tmps);
        }
    }

с выходом

name=Konstantina Pavlova Rusenkova
tmps:Konstantina
  [Konstantina]
tmps:Pavlova
  [Pavlova]
tmps:Rusenkova
  [Rusenkova]
...