Mathematica正则表达式在Unicode字符串上的应用

4
这是一次非常有趣的调试经历。你能发现以下两行代码之间的区别吗?
StringReplace["–", RegularExpression@"[\\s\\S]" -> "abc"]
StringReplace["-", RegularExpression@"[\\s\\S]" -> "abc"]

当您对它们进行评估时,它们会执行非常不同的操作。事实证明,这是因为第一行中要替换的字符串由一个Unicode短划线组成,而第二行则由一个普通的ASCII短划线组成。

对于Unicode字符串,正则表达式无法匹配。 我原本想使用“[\s\S]”表示“匹配任何字符(包括换行符)”,但Mathematica显然将其视为“匹配任何 ASCII 字符”。

我该如何修复正则表达式,使上面的第一行与第二行执行相同?或者,我可以先应用asciify过滤器到字符串上吗?

附注:Mathematica文档指出,它的字符串模式匹配是建立在Perl-Compatible Regular Expressions库(http://pcre.org)之上的,因此我遇到的问题可能并不特定于Mathematica。


1
我不知道为什么这个旧问题会出现为活跃状态,但是问题似乎已经在版本10中得到解决,现在两者都可以工作。顺便提一下,在Mathematica中,Unicode en dash的键入方式为":2013"。 - agentp
3个回答

3
这里有一个asciify函数,我最初使用它作为解决方案:
f[s_String] := s
f[x_] := FromCharacterCode[x]

asciify[s_String] := 
  StringJoin[f /@ (ToCharacterCode[s] /. x_?(#>255&) :> "&"<>ToString[x]<>";")]

然后我意识到,多亏了@Isaac的回答,"."作为正则表达式似乎没有这个unicode问题。从Bug in Mathematica: regular expression applied to very long string的答案中,我学到了 "(.|\n)" 是不明智的,但是建议使用"(?s)."。所以我认为最好的修复方法如下:

StringReplace["–", RegularExpression@"(?s)." -> "abc"]

1
你引用的其他问题/答案很有趣。根据那里的内容,我倾向于认同 "(?s)." 可能更好,尽管在阅读这些答案时,问题可能仅限于 "(.|\n)*"(带有 *)。 - Isaac

3
我会使用StringExpression来替换RegularExpression。这样可以达到预期效果:
f[s_String] := StringReplace[s, _ -> "abc"]

在一个StringExpression中,Blank[]会匹配任何东西,包括非ASCII字符。 编辑针对版本更新:从Mathematica 11.0.1开始,看起来字符编码最高为2^16 - 1的字母字符(这被称为FromCharacterCode的最大值),StringMatchQ[LetterCharacter]的结果现在与LetterQ的结果相匹配。
AllTrue[FromCharacterCode /@ Range[2^16 - 1], 
 LetterQ@# === StringMatchQ[#, LetterCharacter] &]
(* True *)

2
如在《使用字符串模式》教程[1]中所述,在“RegularExpression versus StringExpression”下,字符串模式_RegularExpression["(?s)."]是等价的。[1] http://reference.wolfram.com/mathematica/tutorial/WorkingWithStringPatterns.html - Michael Pilat

1

对于RegularExpression的输入,使用"(.|\n)"似乎对我有效。该模式匹配.(任何非换行符字符)或\n(换行符字符)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接