拆分字符串但保留 C 中的分隔符

时间:2021-07-08 01:16:19

标签: c

我想按字母字符拆分字符串。我从 strtok

开始
char str[] = "A89 99B0 C11D98 9";
char delim[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

char *ptr = strtok(str, delim);

while(ptr != NULL)
{
    printf("%s\n", ptr);
    ptr = strtok(NULL, delim);
}

但我需要保留分隔符。类似的东西

A89 99
B0 
C11
D98 9

我怀疑 strtok 是否可行,我应该寻找另一种方法(例如,正则表达式)。

我想到的一个可能的解决方案是在字符串中的每个字母字符之前插入一个非字母数字分隔符,然后使用 strtok 作为这个分隔符。

4 个答案:

答案 0 :(得分:3)

这取决于您对数据的处理方式,因为您很可能不需要构造实际的字符串。如果您可以避免复制数据以包含空终止符,则它可能很有用。例如:

#include <stdio.h>
#include <string.h>
char str[] = "A89 99B0 C11D98 9";
char delim[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

int
main(void)
{
        char *ptr = str;
        while( *ptr ){
                size_t next = strcspn(ptr + 1, delim) + 1;
                fwrite(ptr, 1, next, stdout);
                putc('\n', stdout);
                ptr += next;
        }
}

答案 1 :(得分:2)

如何使用 strtok 的结果作为字符串完整副本的掩码?

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

int main()
{   
    char str[] = "A89 99B0 C11D98 9";
    char delim[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    char *str_dup = strdup(str);

    if (str_dup != NULL)
    {
        char *ptr = strtok(str, delim);

        while(ptr != NULL)
        {
            int field_len = strlen(ptr) + 1;
            char *field_start = str_dup + (ptr - str) - 1;

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

            ptr = strtok(NULL, delim);
        }

        free (str_dup);
    }

    return 0;
}   

答案 2 :(得分:1)

也许是字符串遍历,试试

// Pseudocode
for (int i = 0; i < strlen(str); i++) {
    if (isalpha(str[i])) printf("\n");
    printf("%c", str[i]);
}

答案 3 :(得分:1)

如果您只想将字符打印到屏幕上,那么您可以遍历字符串并打印位,但是如果您需要实际标记字符串以便稍后使用它,您有两种选择(即我在评论中提到过):

  1. 如果你想做一个 strtok 类型的标记化,你最终得到一个 NUL 终止的字符串,在各个部分之间包含 NUL 终止符,那么你可以就地进行,也可以创建一个新的字符串。为了做出决定,您需要知道将创建的新字符串的大小。然后,如果原始字符串的缓冲区足够大,您可以就地进行,如果不是,则调用者可以分配足够大的内容并将其传入。要测量新字符串的大小,您可以使用与 sprintf 相同的技巧,如果输出字符串是 NULL 指针,则可以返回大小,如果不是,则只需填写即可。

  2. 您可以跳过测量步骤并让函数在内部决定输入字符串是否有空格。您将传递一个 NULL 指针作为输出字符串,如果可以,该函数将就地执行此操作,并且输出指针将保持为 NULL,或者它将分配所需的空间并且输出指针将指向新字符串。该函数可以以任何一种方式返回输出字符串,这可能比返回大小作为返回值更有用,并且调用者会知道它是否必须根据输出指针的值释放空间。

  3. 如果您希望标记化的输出作为实际的字符串数组,您始终可以传递一个 NULL 指针作为输出缓冲区,并让函数在内部分配所有部分。调用者总是不得不释放这些碎片,因为没有选择就地进行。

这个例子展示了我将如何做#1:

// if output is not NULL this will take an input and a delimiter
// and construct a NUL terminated set of NUL terminated strings into output
// and return the size of the whole thing
//
// if output is not NULL this will only calculate how much space would be used
// and then return the size of the whole thing
long tokenise(char *output, char *input, char *delimiters)
{
    long length, size = 0;
    char *next, *current = input, *destination = output;
    
    while(next = strpbrk(current+1,delimiters))
    {
        length = next-current;
        if(destination) // if we aren't just measuring
        {
            if(output == input)
                strcpy(destination+length+1,next++); // if we are doing it in-place
            else
                strncpy(destination,current,length); // if we are making a new string
            destination[length] = '\0';
            destination += length+1;
        }
        size += length+1; // +1 = single NUL
        current = next;
    }
    
    length = strlen(current);
    if(destination) // if we aren't just measuring
    {
        if(output != input)
            strncpy(destination,current,length); // if we are making a new string
        destination[length] = '\0';
        destination[length+1] = '\0';
    }
    return size+length+2; // +2 = double NUL
}

并迭代,打印字符串:

char *pointer = output;
while(*pointer)
{
    puts(pointer);
    pointer += strlen(pointer)+1;
}

https://www.onlinegdb.com/4upvpivar 尝试

并重用上面相同的标记化函数,您可以像这样执行 #2:

char* onesteptokenise(char **output, char *input, long input_max, char *delimiters)
{
    long size = tokenise(NULL,input,delimiters); // measure the size
    if (size<=input_max)
    {
        // do it in place
        *output = NULL;
        tokenise(input,input,delimiters);
        return input;
    }
    else
    {
        // make a new string
        *output = malloc(size);
        if (*output) tokenise(*output,input,delimiters);
        return *output;
    }
}

https://onlinegdb.com/IW_h9hiNV 尝试