【发布时间】:2015-04-13 01:46:44
【问题描述】:
我想知道我们是否会将字符串拆分为标记或任何其他有效的方法。
即我有...
char string1[] = "hello\tfriend\n";
如何在各自独立的变量中获得“hello”和“friend”?
【问题讨论】:
-
主要有 2 种方式:(1) 使用
strtok或 (2) 使用简单的指针来标识每个单词的开头和单词后面的分隔符。
我想知道我们是否会将字符串拆分为标记或任何其他有效的方法。
即我有...
char string1[] = "hello\tfriend\n";
如何在各自独立的变量中获得“hello”和“friend”?
【问题讨论】:
strtok 或 (2) 使用简单的指针来标识每个单词的开头和单词后面的分隔符。
这是一个非常简单的示例,使用开始和结束指针将字符串拆分为保存在字符数组数组中的部分。 MAXL 和 MAXW 定义只是一种方便的方法来定义用于将单个单词长度限制为 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(),因为它会修改它分析的字符串,并且字符串文字通常是不可修改的。
ep++; 之后添加if (!ep) strcpy (strings[idx], sp); 并重试。指针很简单,您只需要考虑它们指向的位置。学习时,将字符串写在纸上并用手跟随每个循环会有所帮助。一切都变得清晰。:p
(!*ep) strcpy (strings[idx], sp);(解除引用对于检查是否到达了结束的空终止符很重要)