【问题标题】:C: strings and pointers. changing sub-strings within a string in a specific patternC:字符串和指针。以特定模式更改字符串中的子字符串
【发布时间】:2012-07-20 08:23:48
【问题描述】:

我很难理解我应该如何执行以下操作:

我有一个这样定义的单词列表:

typedef struct _StringNode {
  char *str;
  struct _StringNode* next;
} StringNode;

现在我需要编写一个函数来接收一个字符串和两个相同长度的单词列表,并且我需要用第二个列表中的相应单词替换字符串中第一个列表中出现的每个单词。

例子:

        text: "stack overflow siteoverflow oveflow stack"
    patterns: [ "stack", "overflow", "site" ]
replacements: [ "Hello", "guys", "here" ]
      result: "Hello guys hereguys guys Hello"

对于每个单词:我正在尝试使用strstr(),因此我将获得一个指向字符串副本中出现的单词的指针,然后更改单词,并提升副本的指针文本字符串。

char* replace(const char *text,
              const StringNode *patterns,
              const StringNode *replacements);

【问题讨论】:

  • 每个节点有一个单词,两个列表包含相同数量的节点。我把代码删了,感觉不对。
  • 旁注,不要使用以_ 开头后跟大写字母的名称。他们是reserved。在 C 中,您可以安全地编写 typedef struct StringNode { ... } StringNode;
  • 我在列表中添加了 Python 风格的语法并引用了字符串,以使其更清晰。
  • 您希望替换文本中模式的任何匹配项,还是个单词(即被空格包围的匹配项)?
  • 如果 [ "a", "a" ] => [ "b", "c" ] 或者更糟糕的是 [ "a", "b" ] => [ " b", "a" ]?

标签: c string parsing


【解决方案1】:

你可以用这个

char *strnreplace(char *st,const int length, 
                  const char *orig,const char *repl) {

  static char buffer[length];
  char *ch;

  if (!(ch = strstr(st, orig)))
      return st;

  strncpy(buffer, st, ch-st);
  buffer[ch-st] = 0;
  sprintf(buffer+(ch-st), "%s%s", repl, ch+strlen(orig));
  return buffer;
}


void replace(const char *text,
              const StringNode *patterns,
              const StringNode *replacements)
{
  StringNode *pat, *rep;
  char *temp = text;
  int length = strlen(text);
  for( pat = patterns, rep = replacements;
        pat->next != NULL;
        pat = pat->next, rep = rep->next ) {
        temp = strnreplace(temp, length, pat->str, rep->str);
  }
}

【讨论】:

    【解决方案2】:

    大概是这样的:

    char* replace(const char *text,
                  const StringNode *patterns,
                  const StringNode *replacements)
    {
      char *out = malloc(1024), *put = out;
    
      while(*text != '\0)
      {
        const StringNode *piter, *riter;
        int found = 0;
    
        /* Check if current start of text matches any pattern. */
        for(piter = patterns, riter = replacements;
            piter != NULL;
            piter = piter->next, riter = riter->next)
        {
          const size_t plen = strlen(piter->str);
          if(strncmp(text, piter->str, plen) == 0)
          {
            /* Hit found, emit replacement. */
            const size_t rlen = strlen(riter->str);
            memcpy(out, riter->str, rlen);
            out += rlen;
            text += plen;
            found = 1;
            break;
          }
        }
        if(!found)
          *put++ = *text++;
      }
      *put = '\0';
    
      return out;
    }
    

    请注意,上述处理缓冲区溢出,为简洁起见省略。我建议在动态字符串数据类型之上实现类似的东西,以使核心操作(追加)根据需要自动增长目标字符串。

    更新针对评论,上面试图实现的算法是:

    set output to empty string
    while text remaining
      if start of text matches pattern[i]
        append replacement[i] to output
        remove len(pattern[i]) characters from start of text
      else
        append first character of text to output
        remove first character of text
    

    因此,它反复检查模式匹配,只要text 中还有任何内容。

    【讨论】:

    • 感谢您的回答。但是看起来每当你找到一个匹配piter->str的子字符串时,你就改变它并继续下一个单词,但是如果文本中有更多单词piter->str子字符串怎么办?
    • @Numerator 我添加了算法的大纲,希望它可以帮助您理解它。简而言之,它会检查text 的每个字符的模式匹配,因此它会在涉及到它们时找到任何以后的匹配。
    • 非常感谢@unwind。很有帮助。我会努力的:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    • 1970-01-01
    • 2013-07-18
    • 2013-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多