【问题标题】:Splitting strings in language C用 C 语言分割字符串
【发布时间】:2015-04-13 01:46:44
【问题描述】:

我想知道我们是否会将字符串拆分为标记或任何其他有效的方法。

即我有...

char string1[] = "hello\tfriend\n";

如何在各自独立的变量中获得“hello”和“friend”?

【问题讨论】:

  • 主要有 2 种方式:(1) 使用 strtok 或 (2) 使用简单的指针来标识每个单词的开头和单词后面的分隔符。

标签: c string token


【解决方案1】:

这是一个非常简单的示例,使用开始和结束指针将字符串拆分为保存在字符数组数组中的部分。 MAXLMAXW 定义只是一种方便的方法来定义用于将单个单词长度限制为 32(31 个字符 + 空终止符)和原始字符串最多 3 个单词(部分)的常量:

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

#define MAXL 32
#define MAXW 3

int main (void) {

    char string1[] = "hello\tfriend\n";
    char *sp = string1;                 /* start pointer        */
    char *ep = string1;                 /* end pointer          */
    unsigned c = 0;                     /* temp character       */
    unsigned idx = 0;                   /* index for part       */
    char strings[MAXW][MAXL] = {{0}};   /* array to hold parts  */

    while (*ep)                         /* for each char in string1 */
    {
        if (*ep == '\t' || *ep == '\n') /* test if \t or \n         */
        {
            c = *ep;                    /* save character           */
            *ep = 0;                    /* replace with null-termator   */
            strcpy (strings[idx], sp);  /* copy part to strings array   */
            *ep = c;                    /* replace w/original character */
            idx++;                      /* increment index          */
            sp = ep + 1;                /* set start pointer        */
        }
        ep++;                           /* advance to next char     */
    }

    printf ("\nOriginal string1 : %s\n", string1);

    unsigned i = 0;
    for (i = 0; i < idx; i++)
        printf ("  strings[%u] : %s\n", i, strings[i]);

    return 0;
}

输出

$ ./bin/split_hello

Original string1 : hello        friend

  strings[0] : hello
  strings[1] : friend

使用strtok 只是将手动指针逻辑替换为函数调用来拆分字符串。


更新的行尾处理示例

正如您所发现的,在单步执行字符串时,您可以根据需要创建一个简单的示例来适应当前字符串,但是通过一些额外的努力,您可以扩展您的代码以处理更广泛的情况。在您的评论中,您注意到上述代码无法处理字符串末尾没有 newline 的情况。与其更改代码来处理这种情况,不如稍微考虑一下,您可以改进代码以处理这两种情况。一种方法是:

    while (*ep)                         /* for each char in string1 */
    {
        if (*ep == '\t' || *ep == '\n') /* test if \t or \n         */
        {
            c = *ep;                    /* save character           */
            *ep = 0;                    /* replace with null-termator   */
            strcpy (strings[idx], sp);  /* copy part to strings array   */
            *ep = c;                    /* replace w/original character */
            idx++;                      /* increment index          */
            sp = ep + 1;                /* set start pointer        */
        }
        else if (!*(ep + 1))  {         /* check if next is ending  */
            strcpy (strings[idx], sp);  /* handle no ending '\n'    */
            idx++;
        }

        ep++;                           /* advance to next char     */
    }

在任何格式/非打印字符上中断

继续拓宽可用于分隔字符串的字符,而不是使用离散值来识别哪些字符分隔单词,您可以使用一系列 ASCII 值来识别所有非打印或格式字符作为分隔符。可以使用稍微不同的方法:

    char string1[] = "\n\nhello\t\tmy\tfriend\tagain\n\n";
    char *p = string1;                  /* pointer to char      */
    unsigned idx = 0;                   /* index for part       */
    unsigned i = 0;                     /* generic counter      */
    char strings[MAXW][MAXL] = {{0}};   /* array to hold parts  */

    while (*p)                          /* for each char in string1 */
    {
        if (idx == MAXW) {              /* test MAXW not exceeded   */
            fprintf (stderr, "error: MAXW (%d) words in string exceeded.\n", MAXW);
            break;
        }

        /* skip each non-print/format char */
        while (*p && (*p < ' ' || *p > '~'))
            p++;

        if (!*p) break;                 /* if end of s, break       */

        while (*p >= ' ' && *p <= '~')  /* for each printable char  */
        {
            strings[idx][i] = *p++;     /* copy to strings array    */
            i++;                        /* advance to next position */
        }

        strings[idx][i] = 0;            /* null-terminate strings   */
        idx++;                          /* next index in strings    */
        i = 0;                          /* start at beginning char  */
    }

这将处理您的测试字符串,而不管行结束和包含的制表符或换行符的数量。看看ASCII Table and Description 作为所用字符范围的参考。

【讨论】:

  • 请注意,您不能可靠地在字符串文字上使用strtok(),因为它会修改它分析的字符串,并且字符串文字通常是不可修改的。
  • 嗯,是的。您还应该首先制作字符串的副本,以防止您的原始文件中到处都是以空字符结尾的字符。好点。
  • 嗨,我尝试了你的建议,我想知道,如果文本只是“hello\tfriend”怎么办。当我尝试做 strings[1] 时,它不会出来。谢谢!
  • 这是一个相当具体的例子,但为了涵盖没有换行符的情况,在ep++; 之后添加if (!ep) strcpy (strings[idx], sp); 并重试。指针很简单,您只需要考虑它们指向的位置。学习时,将字符串写在纸上并用手跟随每个循环会有所帮助。一切都变得清晰。:p
  • 呃,应该是(!*ep) strcpy (strings[idx], sp);(解除引用对于检查是否到达了结束的空终止符很重要)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-09
  • 2015-12-09
  • 1970-01-01
  • 2022-09-28
  • 2015-01-21
  • 2012-03-18
相关资源
最近更新 更多