C изменить строку между символами - PullRequest
1 голос
/ 14 июля 2020

Предположим, у меня есть строка «hello_from_here». Я хотел бы изменить подстроку, которая находится между "_", например "hello_21223_here".

Я полагаю, что мне следует использовать strtok, но пока мне это не удалось.

До сих пор я пытался сделать:

char input[] = "this_is_name";
char* first_part = strtok(input, "_");
char* second_part = strtok(strtok(input, "_"), "_");
char output[64];
int pos = 44;
snprintf(output,sizeof(output),"%s%06d%s", first_part, pos, second_part);

Я знаю, что snprintf правильный, но у меня не получается strtok.

Результат:

this000044this

Моя цель:

this000044name

Ответы [ 5 ]

1 голос
/ 14 июля 2020

strtok возвращаемое значение:

Эта функция возвращает указатель на первый токен, найденный в строке. Если для извлечения не осталось маркеров, возвращается нулевой указатель.

Поскольку вы передаете input в качестве первого аргумента второго strtok, он сбрасывает позицию указателя.

Способ решить эту проблему - передать нулевой указатель в следующем strtok, в данном случае дважды, так как вы хотите пропустить токен is:

//...
char *first_part = strtok(input, "_");
char *second_part = strtok(NULL, "_");
second_part = strtok(NULL, "_");
//...

Живая демонстрация

1 голос
/ 14 июля 2020

Это моя попытка

#include <stdio.h>

void replacemarks(char *dst, const char *src, char c, const char *r) {
    while (1) {
        while (*src && (*src != c)) *dst++ = *src++;
        if (*src == 0) break;
        *dst++ = *src++;
        if (*src == 0) break;
        const char *cc = strchr(src + 1, c);
        if (cc) {
            const char *rr = r;
            while (*rr) *dst++ = *rr++;
            src = cc;
            *dst++ = *src++;
        } else {
            while (*src) *dst++ = *src++;
            break;
        }
    }
    *dst = 0;
}

int main(void) {
    char line[100];
    while (fgets(line, sizeof line, stdin)) {
        char src[100], c, r[100], dst[100];
        sscanf(line, "%s %c%s", src, &c, r);
        replacemarks(dst, src, c, r);
        printf("replacemarks(..., \"%s\", '%c', \"%s\") ==> \"%s\"\n",
              src, c, r, dst);
    }
    return 0;
}

См. https://ideone.com/LhJaaq

Пример запуска с входом

hello_from_here _ 21223
this_is_name _ 000044
abracadabra r foo
*one*two*three* * ----
*one*two*three*four* * ----
*one*two*three*four * ----
one*two*three*four* * ----
*one*two*three*four*five* * ----
*one*two*three*four*five * ----
one*two*three*four*five* * ----

Выход (украшен для Переполнение стека):

replacemarks(..., "hello_from_here", '_', "21223")          ==> "hello_21223_here"
replacemarks(..., "this_is_name", '_', "000044")            ==> "this_000044_name"
replacemarks(..., "abracadabra", 'r', "foo")                ==> "abrfoora"
replacemarks(..., "*one*two*three*", '*', "----")           ==> "*----*two*----*"
replacemarks(..., "*one*two*three*four*", '*', "----")      ==> "*----*two*----*four*"
replacemarks(..., "*one*two*three*four", '*', "----")       ==> "*----*two*----*four"
replacemarks(..., "one*two*three*four*", '*', "----")       ==> "one*----*three*----*"
replacemarks(..., "*one*two*three*four*five*", '*', "----") ==> "*----*two*----*four*----*"
replacemarks(..., "*one*two*three*four*five", '*', "----")  ==> "*----*two*----*four*five"
replacemarks(..., "one*two*three*four*five*", '*', "----")  ==> "one*----*three*----*five*"
0 голосов
/ 14 июля 2020

Вы можете попробовать это:

  char input[] = "this_is_name";
  char *token, *first_part,*second_part, *third_part;
  char output[64];
  int pos = 44;
  token = strtok (input, "_");
  first_part = token;
  token = strtok (NULL, "_");
  second_part = token;
  token = strtok (NULL, "_");
  third_part = token;

  snprintf (output, sizeof (output), "%s%06d%s", first_part, pos,
        third_part);

или что-то вроде этого:

  char input[] = "this_is_name";
  char *part[3];
  char *token;
  char output[64];
  int pos = 44;
  
  token = strtok (input, "_");
  part[0] = token;
  
  int i = 1;
  while (token != NULL && i < 3) {
    token = strtok (NULL, "_");
    part[i] = token;
    i++;
  }

  snprintf (output, sizeof (output), "%s%06d%s", part[0], pos, part[2]);
0 голосов
/ 14 июля 2020

Ну, достаточно хорошо, но:

  • вам нужно запускать strtok на входе, а не на выходе ...
  • Я бы просто использовал strchr здесь
  • Вам нужно указать, сколько символов копировать из first_part, иначе будет скопирована вся строка.
  • Первая часть начинается с начала. Вторая часть начинается там, где находится первая _.

#include <string.h>
#include <stdio.h>
#include <assert.h>
int main() {
    const char input[] = "this_is_name";
    const char *first_part = input;
    const char *second_part = strchr(first_part, '_');
    assert(second_part != NULL);
    size_t first_part_len = second_part - first_part ;
    second_part++; // advance over '_' character
    const char *third_part = strchr(second_part, '_');
    assert(third_part != NULL);
    third_part++;  // advance over '_' character
    char output[64];
    const int pos = 44;
    snprintf(output, sizeof(output), "%.*s_%06d_%s", (int)first_part_len, first_part, pos, third_part);
    printf("%s\n", output);
}

и короткая версия без переменных, в которой используются strcspn и strrchr для поиска _, без проверки ошибок:

snprintf(output, sizeof(output), 
        "%.*s_%06d%s",  (int)strcspn(input, "_"), input, pos, strrchr(input, '_'));
0 голосов
/ 14 июля 2020

Простая (даже «наивная») функция:

char *replaceDup(const char *haystack, const char *replace, int sep)
{
    char *newstr = malloc(strlen(haystack) + strlen(replace));
    char *wrk = newstr;

    if(newstr)
    {
        while(*haystack && *haystack != sep)
        {
            *wrk++ = *haystack++;
        }
        if(*haystack) haystack++;
        while(*haystack && *haystack != sep)
        {
            haystack++;
        }
        if(*haystack) haystack++;
        while(*replace)
        {
            *wrk++ = *replace++;
        }
        while(*haystack)
        {
            *wrk++ = *haystack++;
        }
        *wrk = 0;
    }
    return newstr;
}
...