【发布时间】:2009-10-03 23:54:41
【问题描述】:
如何在 C 中去掉所有 \n 和 \t 的字符串?
【问题讨论】:
如何在 C 中去掉所有 \n 和 \t 的字符串?
【问题讨论】:
这适用于我的快速而肮脏的测试。是否到位:
#include <stdio.h>
void strip(char *s) {
char *p2 = s;
while(*s != '\0') {
if(*s != '\t' && *s != '\n') {
*p2++ = *s++;
} else {
++s;
}
}
*p2 = '\0';
}
int main() {
char buf[] = "this\t is\n a\t test\n test";
strip(buf);
printf("%s\n", buf);
}
为了安抚克里斯,这里有一个版本,它将把结果放在一个新的malloced 缓冲区中并返回它(因此它适用于文字)。您需要free 结果。
char *strip_copy(const char *s) {
char *p = malloc(strlen(s) + 1);
if(p) {
char *p2 = p;
while(*s != '\0') {
if(*s != '\t' && *s != '\n') {
*p2++ = *s++;
} else {
++s;
}
}
*p2 = '\0';
}
return p;
}
【讨论】:
main() 的第一行更改为 char *buf = ...; 怎么办?如果这用于更复杂的代码并且编码人员忘记了哪些参数是可写缓冲区,哪些不是?
char* 或char[] 会有什么不同。另外,strip 中有一个错误:字符串不是以空值结尾的。
char *buf = "hello\tworld" 的东西很感兴趣,这是非法的,因为您不能修改指向文字的指针。我的strip_copy 地址。
如果你想用别的东西替换\n或\t,你可以使用函数strstr()。它返回一个指向具有特定字符串的函数中第一个位置的指针。例如:
// Find the first "\n".
char new_char = 't';
char* pFirstN = strstr(szMyString, "\n");
*pFirstN = new_char;
您可以在循环中运行它以查找所有 \n 和 \t。
如果您想“剥离”它们,即从字符串中删除它们,您实际上需要使用与上述相同的方法,但每次复制字符串“back”的内容当你找到 \n 或 \t 时,“this i\ns a test”变成:“this is a test”。
您可以使用 memmove(不是 memcpy,因为 src 和 dst 指向重叠的内存)来做到这一点,如下所示:
char* temp = strstr(str, "\t");
// Remove \n.
while ((temp = strstr(str, "\n")) != NULL) {
// Len is the length of the string, from the ampersand \n, including the \n.
int len = strlen(str);
memmove(temp, temp + 1, len);
}
您需要再次重复此循环以删除 \t。
注意:这两种方法都可以在原地工作。 这可能不安全! (请阅读 Evan Teran 的 cmets 了解详细信息。。此外,这些方法效率不高,尽管它们确实为某些代码使用了库函数,而不是使用您自己的代码。
【讨论】:
memmove() 遗憾的是相对未知。
基本上,您有两种方法可以做到这一点:您可以创建原始字符串的副本,减去所有 '\t' 和 '\n' 字符,或者您可以“就地”剥离字符串。不过,我敢打赌,第一种选择会更快,而且我向您保证它会更安全。
所以我们要创建一个函数:
char *strip(const char *str, const char *d);
我们想使用strlen() 和malloc() 分配一个与str 缓冲区大小相同的新char * 缓冲区。然后我们逐个字符地遍历str。如果字符 not 包含在d 中,我们将其复制到我们的新缓冲区中。我们可以使用strchr() 之类的东西来查看每个字符是否在字符串d 中。完成后,我们有一个新缓冲区,旧缓冲区的内容减去字符串d 中的字符,所以我们只返回它。我不会给你示例代码,因为这可能是家庭作业,但这里是示例用法,向你展示它如何解决你的问题:
char *string = "some\n text\t to strip";
char *stripped = strip(string, "\t\n");
【讨论】:
这是一个 c 字符串函数,它将查找 accept 中的任何字符并返回指向该位置的指针,如果找不到则返回 NULL。
#include <string.h>
char *strpbrk(const char *s, const char *accept);
例子:
char search[] = "a string with \t and \n";
char *first_occ = strpbrk( search, "\t\n" );
first_occ 将指向 \t 或 search 中的第 15 个字符。您可以替换然后再次调用以循环遍历,直到全部替换为止。
【讨论】:
我喜欢让标准库做尽可能多的工作,所以我会使用与 Evan 的解决方案类似的东西,但使用 strspn() 和 strcspn()。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SPACE " \t\r\n"
static void strip(char *s);
static char *strip_copy(char const *s);
int main(int ac, char **av)
{
char s[] = "this\t is\n a\t test\n test";
char *s1 = strip_copy(s);
strip(s);
printf("%s\n%s\n", s, s1);
return 0;
}
static void strip(char *s)
{
char *p = s;
int n;
while (*s)
{
n = strcspn(s, SPACE);
strncpy(p, s, n);
p += n;
s += n + strspn(s+n, SPACE);
}
*p = 0;
}
static char *strip_copy(char const *s)
{
char *buf = malloc(1 + strlen(s));
if (buf)
{
char *p = buf;
char const *q;
int n;
for (q = s; *q; q += n + strspn(q+n, SPACE))
{
n = strcspn(q, SPACE);
strncpy(p, q, n);
p += n;
}
*p++ = '\0';
buf = realloc(buf, p - buf);
}
return buf;
}
【讨论】: