【问题标题】:how do I remove the substring of a String in C如何在C中删除字符串的子字符串
【发布时间】:2018-05-23 19:19:30
【问题描述】:

我很难在 C 中获取字符串的子字符串。例如,如果我有一个

char *buff = "cat –v <  x y z | ";
char *p = strtok (buff, " ");
while (p != NULL)
{
    if (!strcmp(p, "<") && !isredirected)
    {
        isredirected = 1;
        infileindex  = tokenscounter + 1;
        inputredirectionindex = tokenscounter;
    }
    commandsArray[tokenscounter++]  = p;
    p = strtok (NULL, " ");

}

从这个 buff 字符串中,我想删除 ' 和 '|' 之间的任何字符串。即删除 x y z 。我使用 strtok 解析所有标记,但无法删除 x y z。在我找到 ' 之后,我想删除 之后和 |

之前的所有标记

【问题讨论】:

  • 你期望什么结果,你实际做了什么?请出示代码。
  • 看起来像是正则表达式的工作。
  • 请注意 buff 指向一个不能被修改的字面量,使用 char buff[] = ...
  • 你不能“删除”,但你可以构造一个新的字符串。
  • 找到&lt;|strstr 的位置,然后组装这两个部分。

标签: c


【解决方案1】:

我通常会为此推荐正则表达式,当然不是strtok,更不用说字符串文字(未定义的行为,请参阅C's strtok() and read only string literals

只有基本库的一种解决方案是:

  • 查找起始字符串/字符
  • 查找结束字符串/字符
  • 用起始字符串之前的部分与结束字符串之后的部分组合来重建一个字符串(长或短)。

我为此使用strstr。它是内置的,不需要循环,适用于多字符模式。

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

int main()
{
  const char *buff = "cat -v <  x y z | hello";
  const char *start_pattern = "<";
  const char *end_pattern = "|";

  const char *start = strstr(buff,start_pattern);
  if (start)
  {
    const char *end = strstr(start,end_pattern);
    if (end)
    {
    // allocate enough memory
    char *newbuff = malloc(strlen(buff)+1);

    int startlen = start-buff;   // length of the start of the string we want to keep

    strncpy(newbuff,buff,startlen);  // start of the string
    strcpy(newbuff+startlen,end+strlen(end_pattern));  // end of the string

    printf("Result:%s\n",newbuff);
    free(newbuff);   // free the memory
    }
  }

}

编辑:同时在问题中添加了一些代码。这说明我没有考虑到这一点,因为我试图编写一个不太笨重的解决方案。

【讨论】:

    【解决方案2】:

    另一种方法是一个简单的函数,它遍历源字符串,将不被删除的字符复制到目标字符串,如下所示。

    char *  CopyStringRemove(char *pDest, const char *pSrc)
    {
        // copy the source string, pSrc, to the destination string, pDest, while
        // removing special codes that are between a < character and a | character.
        // we will copy the two special code characters but remove everything in between.
        char * pRet = pDest;
    
        if (pDest) {
            if (pSrc) {
                int   iState = 0;      // state indicates whether copying characters or not.
    
                for (; *pSrc; pSrc++) {
                    switch (*pSrc) {
                    case '<':
                        iState = 1;         // indicate we are skipping characters
                        *pDest++ = *pSrc;   // however copy this character we found
                        break;
                    case '|':
                        iState = 0;     // indicate we are copying characters
                        break;
                    default:
                        break;
                    }
                    switch (iState) {
                    case 0:
                        *pDest++ = *pSrc;    // state is to copy the current character
                        break;
                    case 1:                  // state is to not copy current character, just skip over it.
                        break;
                    }
                }
            }
            *pDest = 0;
        }
    
        return pRet;
    }
    

    这个函数提供了相当大的灵活性,因为源可以是常数,也可以不是常数。目标可能是堆栈上的数组或从堆中分配的数组。如果源数组不是const,那么您可以通过调用CopyStringRemove() 函数进行就地更改,源和目标都是同一个缓冲区。

    它还允许输入问题,例如没有“

    一个测试工具,例如:

    void testfunc(const char *buff)
    {
        {
            char destbuff[128] = { 0 };
            printf("    orig string \"%s\"\n", buff);
            CopyStringRemove(destbuff, buff);
            printf("        new     \"%s\"\n", destbuff);
        }
    
        {
            char destbuff[128] = { 0 };
            char buff2[128] = { 0 };
            strcpy_s(buff2, sizeof(buff2), buff);
            printf("    orig string \"%s\"\n", buff2);
            CopyStringRemove(destbuff, buff2);
            printf("        new     \"%s\"\n", destbuff);
        }
    
        {
            char buff2[128] = { 0 };
            strcpy_s(buff2, sizeof(buff2), buff);
            printf("    orig string \"%s\"\n", buff2);
            CopyStringRemove(buff2, buff2);
            printf("        new     \"%s\"\n", buff2);
        }
    
    }
    
    void main_xfun(void)
    {
        char *buff = "cat -v <  x y z | ";
        char *buffa = "cat -v <  x y z  ";
        char *buffb = "cat -v   x y z | ";
        char *buffc = "cat -v   x y z  ";
    
        printf("\ntest #1\n");
        testfunc(buff);
        printf("\ntest #2\n");
        testfunc(buffa);
        printf("\ntest #3\n");
        testfunc(buffb);
        printf("\ntest #4\n");
        testfunc(buffc);
    }
    

    产生以下结果:

    test #1
        orig string "cat -v <  x y z | "
            new     "cat -v <| "
        orig string "cat -v <  x y z | "
            new     "cat -v <| "
        orig string "cat -v <  x y z | "
            new     "cat -v <| "
    
    test #2
        orig string "cat -v <  x y z  "
            new     "cat -v <"
        orig string "cat -v <  x y z  "
            new     "cat -v <"
        orig string "cat -v <  x y z  "
            new     "cat -v <"
    
    test #3
        orig string "cat -v   x y z | "
            new     "cat -v   x y z | "
        orig string "cat -v   x y z | "
            new     "cat -v   x y z | "
        orig string "cat -v   x y z | "
            new     "cat -v   x y z | "
    
    test #4
        orig string "cat -v   x y z  "
            new     "cat -v   x y z  "
        orig string "cat -v   x y z  "
            new     "cat -v   x y z  "
        orig string "cat -v   x y z  "
            new     "cat -v   x y z  "
    

    【讨论】:

      【解决方案3】:

      (几乎)没有内置解决方案:

      • 要么您想修改就地:在这种情况下,您必须“移动”字符串的末尾(基本上是|);
      • 或创建一个新字符串,复制相关部分并跳过没有的部分。

      【讨论】:

        猜你喜欢
        • 2011-10-15
        • 1970-01-01
        • 2021-04-07
        • 1970-01-01
        • 1970-01-01
        • 2015-11-20
        • 1970-01-01
        • 2020-10-28
        相关资源
        最近更新 更多