【问题标题】:C++/Boost string replace: How do I replace '&' with '&' only when & ends with a ;C++/Boost 字符串替换:仅当 & 以 ; 结尾时,如何将 '&' 替换为 '&'
【发布时间】:2011-07-18 07:13:35
【问题描述】:

我正在替换 xml,只有当 & 字符确实以分号结尾时,我才需要将 & 字符替换为 &

当然,我可以使用 replace_if、replace_all 或 boost 中的正则表达式支持来做到这一点,但我今天感觉很愚蠢……似乎找不到我需要的东西。

建议?

【问题讨论】:

  • &hello world; 怎么样?你需要更多的约束。
  • 在这种情况下,空白将允许匹配,必须是连续的。这是为了 xml 记住哪些不允许 & 不使用 &。我只是不想替换“>”用“>”
  • 听起来更容易替换-`em-all,然后写一个正则表达式替换几个回来。

标签: c++ regex string boost replace


【解决方案1】:

你可以使用否定使用前瞻吗?

/\&(?![A-Za-z]+\;)/

这匹配任何后面没有普通单词加分号的 & 字符。

但是,并非所有系统都支持前瞻。如果你没有,那么你必须首先替换所有 &'s,然后将错误的转换回来。如果没有否定的环顾,正则表达式在 not 匹配某些东西方面根本不好。

【讨论】:

    【解决方案2】:
    1. 将 & 替换为 &
    2. 替换&与&
    3. 利润

    (插入空格以防止 stackoverflow 本身替换它们!)

    【讨论】:

      【解决方案3】:

      我相信 sed 表达式 s/&([^ ]*);/&\1;/g 会做您正在寻找的替代品。我不熟悉 boost 的字符串替换,但是文档说它支持 sed 样式的正则表达式。

      编辑:在 sed 中对其进行测试后,表达式似乎需要更多转义。 s/\&\([^ ]*\);/\&\1;/g 适用于我的测试用例。

      编辑 2:略微改进的表达方式和细分:

      s#&\([^[:space:]]*\);#\&\1;#g

      输入模式:

      & 以文字字符 & 开头

      \([^[:space:]]*\) 匹配并捕获任意数量的非空白字符

      ; 以文字结尾;

      输出模式:

      \& 文字字符 & (需要在输出模式中转义,因为 & 通常代表那里的整个匹配字符串)

      amp; 文字

      \1 打印回捕获的非空白字符字符串

      ; 文字;

      【讨论】:

        【解决方案4】:

        您可以尝试使用以下带有负前瞻的正则表达式:

        (&)(?!\S*;)
        

        仅当 & 后跟非空白字符后跟 ; 时才匹配。

        Perl script using above regex

        我不确定 boost regex 是否允许负前瞻。

        【讨论】:

        • 跟随还是结尾?我的正则表达式生锈了。
        【解决方案5】:

        应该没那么难。使用 std::find 前进到下一个 &,然后 使用 find_if、find_first_of 或 boost::regex 向前扫描以查找 ';',或者会让你停止搜索的东西。某物 像以下(未经测试)应该可以工作:

        struct EndMatch
        {
            bool operator()( char ch ) const
            {
                return isspace( static_cast<unsigned char>( ch ) ) || ch == ';' ;
            }
        };
        
        std::string
        replaceAmp(std::string const& original)
        {
            typedef std::string::const_iterator TextIter;
            std::string results;
            TextIter current = original.begin();
            TextIter end = original.end();
            TextIter next = std::find( current, end, '&' );
            while (next != end) {
                results.append( current, next );
                current = next;
                next = std::find_if( current, end, EndMatch() );
                if ( next == end || *next != ';' ) {
                    results.append( "&amp;" );
                } else {
                    results.append( '&' );
                }
                ++ current;  // Skip '&', processed above
                next = std::find( current, end, '&' );
            }
            results.append( current, next );
            return results;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-02-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-16
          • 2014-06-09
          • 1970-01-01
          相关资源
          最近更新 更多