【问题标题】:Perl - Regex to find and replace ampersands that aren't part of a character entityPerl - 正则表达式查找和替换不属于字符实体的 & 符号
【发布时间】:2015-07-19 12:18:13
【问题描述】:

所以我目前正在使用代码:

$mystring =~ s/&/&/g;   

查找并替换我的字符串变量中的所有与符号 (&),并将它们替换为与符号的 XML 实体引用 (&)。问题是,我只想替换不是 XML 实体引用的一部分的 & 符号。

例如,假设我在此之前进行了查找和替换以使所有“>”成为“>”。

它有一个 & 符号,但我不希望代码的第一位来替换它,因为它后面是 #62;

排除“&#”可能还不够,因为数据中存在合法的可能性很小。那么我可以在正则表达式中排除&符号后跟“#__;”的位置吗?

另外,我要排除的具体三个示例是“,”(逗号)、“>”(>)和“<”(<)。这些是我唯一要做的其他查找和替换,所以如果有办法专门排除这些,那也可以。

谢谢!

【问题讨论】:

  • 您可以使用HTML::Entities 将HTML 实体编码为文本。这样你就不必想出自己的正则表达式,意识到你错过了一个实体,用第二个正则表达式返回,等等。
  • 您没有指定这是 XML 还是 HTML。我假设是 XML,但两者的想法是相似的。根据需要进行修复。
  • Mpost 用户使用& 而不是&。虽然完全有效,但我什至从未见过&
  • 一旦混合,real & 和 special & & 符号实际上在理论上是不可区分的。你应该早点逃脱它们。
  • 你问错问题了。您应该一次性完成所有实体编码。字符串应该是实体编码的,或者不是。混合只是自找麻烦。

标签: regex perl replace find


【解决方案1】:
&(?!#\d+;)

此表达式匹配任何后面没有带数字的哈希字符的 & 字符。

这里是DEMO,有更多解释。

【讨论】:

  • 如果我想修改它以包含任何不带#__的&符号; __ 是任何数字,我该怎么做?作为预防措施,以防我的数据中有任何合法的“”组合
  • $mystring =~ s/&(?!#\d{1,3};)/&/g;会进一步缩小正则表达式
  • 非常感谢,这正是我想要的!非常感谢
【解决方案2】:

XML 字符引用的语法定义为

Reference     ::= EntityRef | CharRef
EntityRef     ::= '&' Name ';'
CharRef       ::= '&#' [0-9]+ ';'
                | '&#x' [0-9a-fA-F]+ ';'
Name          ::= NameStartChar (NameChar)*
NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
NameChar      ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]

因此,如果& 不是有效引用的一部分,则以下内容将转义。

my $name_start_char_class = ':A-Z_a-z\x{00C0}-\x{00D6}\x{00D8}-\x{00F6}\x{00F8}-\x{02FF}\x{0370}-\x{037D}\x{037F}-\x{1FFF}\x{200C}-\x{200D}\x{2070}-\x{218F}\x{2C00}-\x{2FEF}\x{3001}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFFD}\x{10000}-\x{EFFFF}';
my $name_start_char       = qr/[$name_start_char_class]/;
my $name_char             = qr/[${name_start_char_class}\-.0-9\x{00B7}\x{0300}-\x{036F}\x{203F}-\x{2040}]/;
my $name                  = qr/$name_start_char$name_char*/;

s/&(?!(?:$name|#(?:[0-9]+|x[0-9a-fA-F]+));)/&/g

请注意,这假定您的 XML 字符串不包含 CDATA 部分。

【讨论】:

  • 不错的评论帖子。我想知道如何将表达式中的所有标签名称与列表 quot, amp, lt, gt, nbsp, cent, pound, curren, euro 等中的元素匹配
  • @Max Zoom,通常情况下,最好将检查标识符是否已知与实际解析分开。在这种情况下,由于我们正在尝试修复一个错误的文档,它可能会有所帮助。对于 XML:my $name_pat = join '|', qw( amp lt gt quot apos ); my $name = qr/$pat/;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 2021-05-18
  • 1970-01-01
  • 2020-04-18
  • 1970-01-01
  • 1970-01-01
  • 2020-12-22
相关资源
最近更新 更多