C语言 如何在包含句点的同时将句子从较长的字符串复制到新数组中?



我想将字符串的一部分保存到新的字符数组中,同时包含句点。例如,字符串为:

My name is John. I have 1 dog.

我想将每个字符复制到并包括第一个句点,因此新的字符数组将包含:

My name is John.

我在下面写的代码只复制了"我的名字是约翰",但省略了句点。 ptrBeg 和 ptrEnd 分别指向我要复制的部分的开头和结尾的字符。我的目的是通过指向 newBuf 的指针将 ptrBeg 复制到数组 newBuf 中,然后递增 ptrBeg 和指向数组的指针,直到 ptrBeg 和 ptrEnd 指向相同的字符,这应该始终是一个句点。

此时,应该复制字符串的文本,因此我再次将指针递增到 char 数组,并使用

++ptrnewBuf;
*ptrnewBuf = *ptrEnd";

最后,我打印了newBuf的内容。 以下是总代码:

int main()
{
char buf[] = "My name is John. I have 1 dog.";
char * ptrBuf;
char * ptrBeg;
char * ptrEnd;
ptrBeg = buf;
ptrBuf = ptrBeg;
while   (*ptrBuf != '.'){
ptrBuf++;
}
ptrEnd = ptrBuf;
char newBuf[100];
char * ptrnewBuf = newBuf;
while(*ptrBeg != *ptrEnd){
*ptrnewBuf = *ptrBeg;
ptrnewBuf++;
ptrBeg++;
}
++ptrnewBuf;
*ptrnewBuf = *ptrEnd;
printf("%s", newBuf);
}

我将如何修改此代码以包含句点?

你走在正确的轨道上,但你可能会让事情变得比需要的更复杂,并且忽略了一些关键的检查。通过指针或使用指针算法进行迭代的关键是在每次迭代或算术运算期间始终验证和保护数组或内存边界。

另一个提示是在编码所有内容之前始终在一张纸上绘制出指针位置,以便您清楚地了解迭代限制和需要的任何调整。(您不必使用完整的长字符串和许多框,只需使用少数字符表示需要完成的操作(如果您希望通过第一个'.'复制订阅,可以像下面这样简单的事情,例如

+---+---+---+---+---+---+
| A | . |   | B | . | |
+---+---+---+---+---+---+
^   ^
|   pointer (when *p == '.')
buf

因此,要将"A."buf复制到new缓冲区,您不能简单地迭代while (*p != '.')否则您将无法复制'.'。通过将其绘制出来,您可以清楚地看到p == '.'时还需要复制字符,例如

+---+---+---+---+---+---+
| A | . |   | B | . | |
+---+---+---+---+---+---+
^       ^
|   |-->| pointer (p + 1)
buf

现在,无论'.'之前字符串的实际长度如何,您现在都知道需要p + 1作为最终地址才能在副本中包含最后一个字符。

您还知道new缓冲区可以存储多少个字符。假设new的大小为MAXC个字符(最大字符数(。因此,您最多可以存储MAXC-1个字符(加上nul-字符(的字符串。当您填写new时,您需要始终验证您是否在MAXC-1字符范围内。

您还需要确保新字符串以nul 结尾(或者它不是字符串,它只是一个字符数组(。确保 nul 终止的一种有效方法是在声明 new 时初始化 new 中的所有字符以0,例如

char new[MAXC] = "";

将第一个字符初始化为0(例如''空字符串(和所有剩余字符默认0。现在,如果您填写不超过MAXC-1个字符,则可以保证数组将以 nul 结尾的字符串。

总而言之,您可以执行以下操作:

#include <stdio.h>
#define MAXC 128    /* if you need a constant, #define one (or more) */
int main (void) {
char buf[] = "My name is John. I have 1 dog.",
*p = buf,               /* pointer to buf */
new[MAXC] = "",         /* buffer for substring */
*n = new;               /* pointer to new */
size_t ndx = 0;             /* index for new */
/* loop copying each char until new full, '.' copied, or end of buf */
for (; ndx + 1 < MAXC && *p; p++, n++, ndx++) {
*n = *p;        /* copy char from buf to new */
if (*n == '.')  /* if char was '.' break */
break;
}
printf ("buf: %snnew: %sn", buf, new);
return 0;
}

(注意:ndx作为for循环的一部分递增,以跟踪使用指针复制的字符数(

示例使用/输出

$ ./bin/str_cpy_substr
buf: My name is John. I have 1 dog.
new: My name is John.

如果您没有初始化字符串以确保 nul 终止的奢侈,则始终可以在复制完成后肯定地终止 nul。例如,您可以在for循环退出后添加以下内容,以确保正确终止未知初始化数组:

*++n = 0;   /* nul-terminate (if not already done by initialization) and
* note ++n applied before * due to C operator precedence.
*/

仔细查看,如果您有其他问题,请告诉我。

只是将其分解为一个从一行中"提取"第一句话的辅助函数。只需一次复制一个字符,直到在源上命中字符串结尾条件、找到句点或遇到目标缓冲区的最大长度。

void ExtractFirstSentence(const char* line, char* dst, int size)
{
int count = 0;
char c ='';
if ((line == NULL) || (dst == NULL) || (size <= 0))
{
return;
}

while ((*line) && ((count+1) < size) && (c != '.'))
{
c = *line++;
*dst++ = c;
count++;
}
*dst = '';
}
int main()
{
char buf[] = "My name is John. I have 1 dog.";
char newBuf[100];
ExtractFirstSentence(buf, newBuf, 100);
printf("%s", newBuf);
}

如果你想在不处理所有这些指针的情况下更容易一些东西,请尝试:

int main()
{
char buf[] = "My name is John. I have 1 dog.";
int i = 0;
int j = 0;
while(buf[i] != '.' && buf[i] != '') {
i++;
}
char newbuf[i+1];
while (j <= i) {
newbuf[j] = buf[j];
j++;
}
newbuf[j] = '';
printf("%sn",newbuf);
return 0;
}

虽然制作 newbuf 时的 i+1 和 newbuff[j] = '\0' 我不是 100% 确定需要这样。 我的想法是需要 I+1 来为 \0 结尾腾出空间,然后在将 BUF 复制到 newbuf 的 while 循环之后添加。 但我可能弄错了。

你可以使用 strtok(( 来拆分字符串。只需输入man strtok,你会看到:

程序源

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
char *str1, *str2, *token, *subtoken;
char *saveptr1, *saveptr2;
int j;
if (argc != 4) {
fprintf(stderr, "Usage: %s string delim subdelimn",
argv[0]);
exit(EXIT_FAILURE);
}
for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
token = strtok_r(str1, argv[2], &saveptr1);
if (token == NULL)
break;
printf("%d: %sn", j, token);
for (str2 = token; ; str2 = NULL) {
subtoken = strtok_r(str2, argv[3], &saveptr2);
if (subtoken == NULL)
break;
printf(" --> %sn", subtoken);
}
}
exit(EXIT_SUCCESS);
}

此程序生成的输出示例如下:

$ ./a.out 'a/bbb///cc;xxx:yyy:' ':;' '/'
1: a/bbb///cc
--> a
--> bbb
--> cc
2: xxx
--> xxx
3: yyy
--> yyy

相关内容

最新更新