-1

我一直在为 C/C++ 寻找类似 PHP 的str_replace(),但我发现只有为结果分配/重新分配缓冲区的解决方案。在嵌入式环境中,这并不总是可能的,字符串没有内存,甚至没有malloc()。所以我正在寻找一个函数,它使用相同的缓冲区,类似于strncat(),其中最大值。缓冲区大小作为参数给出:

 void str_replace(char* search,char* replace,char* subject,int maxBufferSize);

诀窍是,我刚刚写了一个,我会在一分钟内发布。是的,这是回答我自己问题的典型案例,但我读过它是合法的

无论如何,我会在最佳答案上按下接受按钮。我的解决方案已经过测试,希望效果很好,但还有改进的余地。我相信会有更好的答案。我可以等。

4

2 回答 2

2

这是我的尝试,未经测试:

void str_replace(char *search, char *replace, char *subject, size_t size)
{
    char *end = subject+size;
    size_t sl = strlen(search);
    size_t rl = strlen(replace);
    size_t l = strlen(subject);
    char *src = memmove(end-l-1, subject, l+1);
    char *dest = subject;
    while (*src) {
        char *match = strstr(src, search);
        if (!match) {
            match = src + strlen(src);
            rl = 0;
        }
        memmove(dest, src, match-src);
        dest += match-src;
        src = match+sl;
        memcpy(dest, replace, rl);
        dest += rl;
    }
    *dest = 0;
}

这假设strlen(replace) <= strlen(search). 如果不满足该约束,则需要进行一些额外的检查以确保dest不会通过src,并且替换在复制到位时适合。

该算法应该是避免过多访问(读取和写入)的最佳算法。

于 2013-02-01T20:43:27.127 回答
0

所以,这是我的快速解决方案。它有效,但有问题:

  • 模式被发现不止一次时,剩余部分(收缩/扩展)将在每一轮中被复制;
  • 应该使用memcpy() ;
  • 一些预先计算应该在for语句之外进行。

编辑:为请求添加评论。

    void strReplace(char* pattern,char* replacement,char* buffer,int maxLength) {

      int buflen = strlen(buffer);  // atual string length (changes after each replace)
      int patlen = strlen(pattern);  // pattern length, constant
      int replen = strlen(replacement);  // replacement lengh, constant
      int matlen = (patlen < replen ? patlen : replen);  // length of pattern/replacement mathcing part
      int ptr = 0;  // pointer, runs from 0 to buffer length

      while (true) {

        // find out, if string at buffer[ptr] matches the pattern
        int match = true;
        for (int n = 0; n < patlen; n++) {
          if ((n + ptr) == buflen) return;
          if (buffer[n + ptr] != pattern[n]) {
            match = false;
            break;
          } // if matching
        } // for pattern

        // if not match, increase ptr
        if (!match) {
          ptr++;
          if (ptr > buflen) return;
          continue;
        } // if not match

        // replace the common part (which requires no remaining block move)
        for (int n = 0; n < matlen; n++) buffer[n + ptr] = replacement[n];
        // if we're lucky, the search string is same lenght as replacement
        if (patlen == replen) return;

        // move remaining
        if (patlen > replen) {  // shrink, if repacement was shorter

          int shrink = patlen - replen;
          // perform shrink
          for (int idx = matlen + ptr; idx < buflen - shrink; idx++) {
            buffer[idx] = buffer[shrink + idx];
          }
          // don't forget to close the asciiz string
          buffer[buflen - shrink] = 0;

          // align ptr
          ptr = 1 + ptr - shrink;
          // align buffer
          buflen -= shrink;

        } else {   // expan if replacement is longer

          int expand = replen - patlen;
          int bufend = buflen + expand;  // buffer end after expand
          if (bufend > maxLength - 1) bufend = maxLength - 1;  // apply maxLength

          // make room by copying remaining to the end of the string
          for (int idx = bufend; idx > ptr + matlen + expand; idx--) {
            buffer[idx - 1] = buffer[idx - 1 - expand];
          }
          // fill the hole with the remainig part of the replacement
          for (int n = matlen; n < replen; n++) {
            buffer[n + ptr] = replacement[n];
          }
          // don't forget to close the asciiz string
          buffer[bufend] = 0;

          // align ptr
          ptr = 1 + ptr + expand;
          // align buffer
          buflen = bufend;

        } // if shrink else expand

        // continue from new ptr

      } // scan buffer

    } // strReplace()
于 2013-02-01T19:36:03.477 回答