如何在c语言中截取字符串的一部分?

11

我正在尝试找出如何在C语言中截取字符串的一部分。例如,你有一个字符型字符串 "The dog died because a car hit him while it was crossing the road",如何使用函数将句子变为 "a car hit him while crossing the road" 或者 "a car hit him"。

使用C语言的库(和/或)自定义函数可以实现这个功能。

好的,我没有主代码,但这将是实验的结构。

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include "display_usage.c"/*If the user enters wrong arguments it will tell them how it should be */


void cut( const char *file, int option, int first, int last );


int main(int argc, char *argv[] ) {
FILE *fp;
    char ch;
    fp = fopen("test.txt", "r"); // Open file in Read mode

    while (ch!=EOF) {
        ch = fgetc(fp); // Read a Character

        printf("%c", ch);
    }
    fclose(fp); // Close File after Reading
   return 0;
}

void cut( const char *file, int reverse, int first, int last ) {



    return;
}

展示一下你尝试过的,我们会帮助你。 - Aswin Murugesh
如果您有一个关键词可以切断句子,或者有一个需要切断句子的特定长度,那么这是可能的。 - smac89
9
好的,至少它不是一只鸭子穿过马路。 - Duck
你将如何定义要执行的操作?如果你只对结果字符串感兴趣,那么你可以将它们指定为文字。如果你想更通用地完成任务,你必须指定如何识别你想要删除的内容或保留的内容。你会在单个函数调用中完成吗?你会修改原字符串还是将字符串的部分复制到另一个位置?第一个目标句子有两个删除操作(缺少一个“it”);同样,第二个目标句子也是如此。 - Jonathan Leffler
6个回答

8

strncpy函数只会复制最多n个字符。如果您有可写内存,可以选择在字符串中移动指针,并将\0插入数组以提前终止它。


2
如果源和目标重叠,就不能使用strncpy() - Jonathan Leffler

6
以下函数从char缓冲区中剪切给定范围。该范围由起始索引和长度识别。可以指定负长度以表示从起始索引到字符串结尾的范围。
/*
 *      Remove given section from string. Negative len means remove
 *      everything up to the end.
 */
int str_cut(char *str, int begin, int len)
{
    int l = strlen(str);

    if (len < 0) len = l - begin;
    if (begin + len > l) len = l - begin;
    memmove(str + begin, str + begin + len, l - len + 1);

    return len;
}

通过使用 memmove 函数将范围之后的所有内容(包括终止符'\0')移动到起始索引,从而覆盖该范围,从而删除字符范围。在该范围内的文本将被丢失。

请注意,您需要传递一个可以更改其内容的字符缓冲区。不要传递存储在只读内存中的字符串字面量。


请展示这个函数实际运行的例子。 - MadHatter
我正在尝试在repl中使用这个函数。请帮助我理解如何使用它--我知道参数*str是一个字符串,我也知道参数begin是我想要开始切片的索引地址,但我不知道参数len应该是什么。请帮助我理解并展示这个函数的使用方法。 - MadHatter
len 是要删除的部分的长度。函数中的计算确保 len 不超过实际长度。在此处可以查看其运行情况。(虽然我不确定该函数是否在查找/替换功能中有用。您应该将内容移动,以便在删除单词后,有一个可以容纳替换的空隙。请注意,替换的长度可能比原始单词长。) - M Oehm

3
对于这样的问题,最好编写自己的函数。虽然需要花费时间,但收益会很大。下面是一个名为str_slice的函数代码,它非常类似于JavaScript的函数string.slicehttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice)和Python的用于在字符串或数组上进行切片的特性(https://docs.python.org/3.5/library/functions.html#slice)。此外,它仅基于C标准库,因此必须跨平台并与任何编译器一起使用。如果有疑问,请查看测试。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


/**
 * Extracts a selection of string and return a new string or NULL.
 * It supports both negative and positive indexes.
 */
char *
str_slice(char str[], int slice_from, int slice_to)
{
    // if a string is empty, returns nothing
    if (str[0] == '\0')
        return NULL;

    char *buffer;
    size_t str_len, buffer_len;

    // for negative indexes "slice_from" must be less "slice_to"
    if (slice_to < 0 && slice_from < slice_to) {
        str_len = strlen(str);

        // if "slice_to" goes beyond permissible limits
        if (abs(slice_to) > str_len - 1)
            return NULL;

        // if "slice_from" goes beyond permissible limits
        if (abs(slice_from) > str_len)
            slice_from = (-1) * str_len;

        buffer_len = slice_to - slice_from;
        str += (str_len + slice_from);

    // for positive indexes "slice_from" must be more "slice_to"
    } else if (slice_from >= 0 && slice_to > slice_from) {
        str_len = strlen(str);

        // if "slice_from" goes beyond permissible limits
        if (slice_from > str_len - 1)
            return NULL;

        buffer_len = slice_to - slice_from;
        str += slice_from;

    // otherwise, returns NULL
    } else
        return NULL;

    buffer = calloc(buffer_len, sizeof(char));
    strncpy(buffer, str, buffer_len);
    return buffer;
}

测试

#include <assert.h>

void
test_str_slice()
{
    char str[] = "abcdefghijkl";

    assert(NULL == str_slice(str, -3, -10));
    assert(NULL == str_slice(str, -1, -2));
    assert(NULL == str_slice(str, -1, 0));
    assert(NULL == str_slice(str, 1, 0));
    assert(NULL == str_slice(str, 5, 4));
    assert(NULL == str_slice(str, 0, 0));
    assert(NULL == str_slice(str, 10, 10));
    assert(NULL == str_slice(str, -2, -2));
    assert(NULL == str_slice(str, -20, -12));
    assert(NULL == str_slice(str, -20, -13));
    assert(NULL == str_slice(str, 12, 13));
    assert(NULL == str_slice(str, 12, 20));
    assert(NULL == str_slice("", 1, 2));
    assert(NULL == str_slice("", -2, -1));
    assert(strcmp(str_slice(str, -3, -1), "jk") == 0);
    assert(strcmp(str_slice(str, -8, -3), "efghi") == 0);
    assert(strcmp(str_slice(str, -10, -9), "c") == 0);
    assert(strcmp(str_slice(str, -2, -1), "k") == 0);
    assert(strcmp(str_slice(str, -15, -1), "abcdefghijk") == 0);
    assert(strcmp(str_slice(str, -12, -2), "abcdefghij") == 0);
    assert(strcmp(str_slice(str, -15, -8), "abcd") == 0);
    assert(strcmp(str_slice(str, -15, -11), "a") == 0);
    assert(strcmp(str_slice(str, 1, 3), "bc") == 0);
    assert(strcmp(str_slice(str, 11, 100), "l") == 0);
    assert(strcmp(str_slice(str, 2, 4), "cd") == 0);
    assert(strcmp(str_slice(str, 3, 6), "def") == 0);
    assert(strcmp(str_slice(str, 0, 1), "a") == 0);
    assert(strcmp(str_slice(str, 4, 6), "ef") == 0);
    assert(strcmp(str_slice(str, 1, 2), "b") == 0);
    assert(strcmp(str_slice(str, 0, 3), "abc") == 0);
    assert(strcmp(str_slice(str, 0, 11), "abcdefghijk") == 0);
    assert(strcmp(str_slice(str, 2, 10), "cdefghij") == 0);
    assert(strcmp(str_slice(str, 0, 50), "abcdefghijkl") == 0);
}

从测试结果可以看出,这个函数返回一个字符串或者NULL。它支持负数和正数索引。这个想法来自于JavaScript和Python早期的特性。因此,请不要在答案中添加大量文本,我建议您阅读JavaScript和Python的文档。


1
如果您知道字符串的内容,strstr将非常适合您。
示例:
char *str = "A dog died because a car hit him while he was crossing the road.";
char *pCh = strstr(str, "dog");

pCh将拥有"dog"'d'的地址。


4
strstr 如何缩短一个字符串?它可能会帮助定位需要截取的字符范围,但这并不是提问者所询问的内容。 - M Oehm

0

0

您可以通过简单的代码使用类似于Python的[n:m]切片操作符,但需要动态分配并保留作为输入的原始字符串。

char* cutoff(const char* str, int from , int to)
{
    if (from >= to)
        return  NULL;

    char* cut = calloc(sizeof(char), (to - from) + 1);
    char* begin = cut;
    if (!cut)
        return  NULL;

    const char* fromit = str+from;
    const char* toit = str+to;
    (void)toit;
    memcpy(cut, fromit, to);
    return begin;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接