XML替换C中的特殊字符

时间:2018-03-09 10:01:26

标签: c string memory-management xml-parsing malloc

我试图在图书馆中开发一个功能,以寻找字符'<&#;;'>''和'&&#39 ;;并将其替换为<>&

到目前为止,我已经开发了这个功能:

char *sXMLspecialReplace(char *rawString) {
  char *old_pointer = rawString;
  int new_index = 0;
  /*In most cases there won't be character substitution, so we can
  start allocating with the original length and only reallocate if
  a special char is spotted, therefore, memory reallocation will
  take place in few circumstances.
  + 1 for NULL terminator.*/
  int result_size = strlen(rawString) + 1;
  char *result = (char *) malloc(result_size);
  do {
    switch (*old_pointer) {
      case '&':
        result_size += 4; // From 1 to 5
        result = (char *) realloc(result, result_size);
        strcpy(result + new_index, "&");
        new_index += 5;
        break;
      case '<':
        result_size += 3; // From 1 to 4
        result = (char *) realloc(result, result_size);
        strcpy(result + new_index, "&lt;");
        new_index += 4;
        break;
      case '>':
        result_size += 3; // From 1 to 4
        result = (char *) realloc(result, result_size);
        strcpy(result + new_index, "&gt;");
        new_index += 4;
        break;
      default:
        //Most frequent case
        result[new_index++] = *old_pointer;
    }
    old_pointer++;
  } while (*old_pointer != '\0');
  /*do-while ensures the function exits with a null terminator*/
  return result;
}

虽然它在某些情况下有效,但在有些情况下它还有其他情况。在测试中,我尝试执行以下操作:

char *my_company = "HELLO INDUSTRIES EUROPE";
char *xml_company = sXMLspecialReplace(my_company);

sprintf(sXMLanswer,
  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  "<company>%s</company>\n",
  xml_company);

printf(sXMLanswer);

输出

<?xml version="1.0" encoding="UTF-8"?>
<company>HELLO INDUSTRIES EUROPE[[[[[</company>

编辑1:格式&lt;&gt;&amp;

2 个答案:

答案 0 :(得分:3)

你没有终止你的字符串副本。

do
{
  switch (*old_pointer)
  {
   ...
    default:
      //Most frequent case
      result[new_index++] = *old_pointer;
  }
  old_pointer++;
} while (*old_pointer != '\0');

switch中复制字符。然后你推进你的源指针。 然后检查高级指针是否指向'\0'。 这意味着在字符串的最后一个字符之后,您将离开do while循环,并且不会复制终止'\0'字节。

这会在您复制字符串后留下随机垃圾。

你可能会这样解决:

  ...
  }
  // No incement here!
} while (*old_pointer++ != '\0');

答案 1 :(得分:1)

可能更好(1)在三个单独的步骤中做你想做的事情:

  • 1:获得最终结果的len
  • 2:分配
  • 3:填写

要获得最终的len,它非常简单:您只需遍历字符串,每次看到要替换的字符时,都会相应地增加len。

要填充它,它也非常简单:再次遍历字符串,如果看到一个字符,则添加替换文本而不是原始字符。

鉴于你已经做了什么,我认为这个算法对你来说是件小事。

如果你想保持它基本的,你可以对所有东西进行编码(就像你已经做过的那样),或者你可以使用结构来允许更多的进化代码(比如addind另一个角色来代替)。

编辑:(1)我说&#34;更好&#34;因为你可能最终在运行时做了很多realloc / malloc,这根本不是很有效。此外,每次你想要添加一个替换字符(我不知道XML是否有&#34;&amp;&lt;&gt;&#34;),你将不得不做一个realloc,这将是无所事事地增加你的代码。 想象一下,有23个特征可以替换......你的代码最终会处于维护状态。

typedef struct swap {
    char   src;
    char   *dst;
    size_t dstLen;
} swap_s;

swap_s *SwapList_FoundBySrc(swap_s *list, char searched)
{
    for (size_t i = 0; list[i].src; ++i) {
        if (list[i].src == searched) {
            return (&list[i]);
        }
    }
    return (NULL);
}

char *PlainStringToXmlString(char *input)
{
    char   *output = NULL;
    size_t len     = 1; // Final '\0'
    swap_s list[]  = {{'&',  "&amp;", strlen("&amp;")},
                      {'<',  "&lt;",  strlen("&lt;")},
                      {'>',  "&gt;",  strlen("&gt;")},
                      {'\0', NULL,    0}};
    swap_s *swap   = NULL;

    // Get the final len sum
    for (size_t i = 0; input[i]; ++i) {
        if ((swap = SwapList_FoundBySrc(list, input[i]))) {
            len += swap->dstLen;
        } else {
            ++len;
        }
    }

    // Allocate it
    if (!(output = malloc(len))) {
        // Log ?
        return (NULL);
    }
    output[len - 1] = '\0';

    // Fill it
    size_t j = 0;
    for (size_t i = 0; input[i]; ++i) {
        if ((swap = SwapList_FoundBySrc(list, input[i]))) {
            strcpy(output + j, swap->dst);
            j += swap->dstLen;
        } else {
            output[j] = input[i];
            ++j;
        }
    }

    return (output);
}