【发布时间】:2015-05-07 21:54:46
【问题描述】:
我想知道一个匹配埃及象形文字的正则表达式。我完全一无所知,需要你的帮助。
我无法发布这些字母,因为堆栈溢出似乎无法识别它。
那么谁能告诉我这些字符的 unicode 范围。
【问题讨论】:
-
这显然是关于编程的,任何人都可以从两个充满编程内容的优秀答案中看出!投票重新开放。
标签: regex unicode internationalization
我想知道一个匹配埃及象形文字的正则表达式。我完全一无所知,需要你的帮助。
我无法发布这些字母,因为堆栈溢出似乎无法识别它。
那么谁能告诉我这些字符的 unicode 范围。
【问题讨论】:
标签: regex unicode internationalization
Unicode 在 U+13000 到 U+1342F 的范围内编码 Egyptian hieroglyphs(超出基本多语言平面)。
在这种情况下,有两种写正则表达式的方法:
通过指定从 U+13000 到 U+1342F 的字符范围。
虽然在正则表达式中为 BMP 中的字符指定字符范围就像 [a-z] 一样简单,但取决于语言支持,为星体平面中的字符执行此操作可能不那么简单。
通过为埃及象形文字指定 Unicode 块
由于我们要匹配埃及象形文字块中的任何字符,因此这是编写可用支持的正则表达式的首选方式。
(目前,我不知道 Java 类库的其他实现如何处理 Pattern 类中的星体平面字符。
我不确定在 Java 1.4 中讨论星体平面中的字符匹配是否有意义,因为对 BMP 之外的字符的支持仅在 Java 5 中通过改进现有的 String 实现(它使用 UCS-2内部字符串表示)具有代码点感知方法。
由于 Java 继续允许在 String 中指定单独的代理(不能与其他代理成对),它导致了混乱,因为代理不是真正的字符,单独的代理是无效的在 UTF-16 中。
Pattern 类见证了从 Java 1.4.x 到 Java 5 的重大改革,因为该类被重写以提供对星体平面中匹配 Unicode 字符的支持:模式字符串在被转换为代码点数组之前被转换为代码点数组解析,输入字符串被String类中的码点感知方法遍历。
You can read more about the madness in Java regex in this answer by tchist.
我已经详细解释了如何匹配涉及星体平面字符in this answer的字符范围,所以我只在这里包含代码。它还包括一些错误尝试编写正则表达式以匹配星体平面字符的反例。
"[\uD80C\uDC00-\uD80D\uDC2F]"
"[\\uD80C\\uDC00-\\uD80D\\uDC2F]"
"[\\x{13000}-\\x{1342F}]"
由于我们要匹配任何属于 Unicode 块的代码点,它也可以写成:
"\\p{InEgyptian_Hieroglyphs}"
"\\p{InEgyptian Hieroglyphs}"
"\\p{InEgyptianHieroglyphs}"
"\\p{block=EgyptianHieroglyphs}"
"\\p{blk=Egyptian Hieroglyphs}"
Java 从 1.4 开始支持 Unicode 块的 \p 语法,但仅在 Java 7 中添加了对埃及象形文字块的支持。
georg's answer 中已经介绍了 PHP 示例:
'~\p{Egyptian_Hieroglyphs}~u'
请注意u 标志是强制性的,如果您想通过代码点进行匹配而不是通过代码单元进行匹配。
不确定 StackOverflow 上是否有更好的帖子,但I have written some explanation on the effect of u flag (UTF mode) in this answer of mine。
需要注意的一点是Egyptian_Hieroglyphs 只能从PCRE 8.02 获得(或不早于PCRE 7.90 的版本)。
作为替代方案,您可以使用\x{h...hh} 语法指定字符范围:
'~[\x{13000}-\x{1342F}]~u'
注意强制性的u 标志。
至少从PCRE 4.50 开始支持\x{h...hh} 语法。
georg's answer 已经介绍了字符范围方法(这是原生 JavaScript 中唯一的方法)。正则表达式稍作修改以覆盖整个块,包括保留的未分配代码点。
/(?:\uD80C[\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2F])/
上面的解决方案演示了匹配星界中一系列字符的技术,以及 JavaScript RegExp 的局限性。
JavaScript 也存在与 Java 相同的字符串表示问题。虽然 Java 确实在 Java 5 中修复了 Pattern 类以允许它使用代码点,但 JavaScript RegExp 仍然停留在 UCS-2 时代,迫使我们使用代码单元而不是正则表达式中的代码点.
最后,ECMAScript 6 中添加了对代码点匹配的支持,可通过u 标志获得,以防止破坏以前版本的 ECMAScript 中的现有实现。
查看上面第二个链接中的Support 部分,查看为 ES6 提供实验性支持的浏览器列表RegExp。
随着 ES6 中 \u{h...hh} 语法的引入,字符范围可以用类似于 Java 7 的方式重写:
/[\u{13000}-\u{1342F}]/u
或者你也可以直接指定RegExp字面量中的字符,虽然意图不如[a-z]那么明确:
/[?-?]/u
请注意上述两个正则表达式中的 u 修饰符。
仍然卡在 ES5 上?不用担心,您可以使用regxpu 将 ES6 Unicode RegExp 转换为 ES5 RegExp。
【讨论】:
TLDNR:\p{Egyptian_Hieroglyphs}
Egyptian_Hieroglyphs 属于使用超过 16 位来编码字符的“星体”平面。从 ES5 开始,Javascript 不支持星界 (more on that),因此您必须使用代理对。第一个代理是
U+13000 = d80c dc00
最后一个是
U+1342E = d80d dc2e
给了
re = /(\uD80C[\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E])+/g
t = document.getElementById("pyramid").innerHTML
document.write("<h1>Found</h1>" + t.match(re))
<div id="pyramid">
some ? really ? old ? stuff ? ?
</div>
这是安装了Noto Sans Egyptian Hieroglyphs 后的样子:
在支持 UCS-4 的平台上,您可以直接使用埃及代码点 13000 到 1342F,但语法因系统而异。例如,在 Python(3.3 以上)中,它将是 [\U00013000-\U0001342E]:
>>> s = "some \U+13000 really \U+13001 old \U+1342C stuff \U+1342D \U+1342E"
>>> s
'some ? really ? old ? stuff ? ?'
>>> import re
>>> re.findall('[\U00013000-\U0001342E]', s)
['?', '?', '?', '?', '?']
最后,如果您的正则表达式引擎支持 unicode 属性,您可以(并且应该)使用这些属性而不是硬编码范围。例如在 php/pcre 中:
$str = " some ? really ? old ? stuff ? ?";
preg_match_all('~\p{Egyptian_Hieroglyphs}~u', $str, $m);
print_r($m);
打印
[0] => Array
(
[0] => ?
[1] => ?
[2] => ?
[3] => ?
[4] => ?
)
【讨论】: