【问题标题】:split and replace unicode words in javascript with regex用正则表达式拆分和替换javascript中的unicode单词
【发布时间】:2011-07-30 14:07:46
【问题描述】:

需要将 unicode 单词列表放入 {} 中的 unicode 字符串中。 有我的代码:

var txt = "¿One;one oneé two two two two two twö twöu three;;twä;föur?";
var re = new RegExp("(^|\\W)(one|tw|two two|two|twöu|three|föur)(?=\\W|$)", "gi");
alert(txt.replace(re, '$1 {$2}'));

返回:

¿{一};{一} {一}é {二二} {二二} {二} {tw}ö {tw}öu {三};;{tw}ä;{föur}?

但应该是:

¿{一个};{一个} oneé {二 二} {二二} {二} 二 {twöu} {三};;twä;{föur}?

我做错了什么?

【问题讨论】:

  • 你没有做错任何事——不幸的是。 Javascript 是。一个完美的、符合标准的解决方案在 Javascript 下是不可能的,因为它目前正在实施,但是有一个 Javascript 插件库,在这种特殊情况下,您也许可以选择为您解决问题。请参阅下面的答案。

标签: javascript regex unicode split


【解决方案1】:

首先,除非正则表达式是动态的,否则请使用/.../gi 表示法。

它返回错误值的问题是因为 Javascript 中的 \W 实际上只是 [^0-9a-zA-Z_]。像é 这样的重音字符不被视为单词字符。您需要手动排除它们。

var re = /(^|[^a-zäéö])(one|tw|two two|two|twöu|three|föur)(?=[^a-zäéö]|$)/gi;

【讨论】:

  • 另外,当不使用 Unicode 时,请注意 (?=\W|$) 重写为 \b 更好。 (在这种情况下,您会遇到同样的问题,因为非 ASCII7 字符不被视为单词字符)
  • äéö 符号只是示例。我需要通用解决方案如何从所有语言的标点符号和空格中拆分单词。 Javascript可以吗?
【解决方案2】:

试试这个:

var txt = "¿One;one oneé two two two two two twö twöu three;;twä;föur?";
var re = new RegExp("(^|\\W)(one|two two|two|twöu|three|föur)(?=[^a-zé]|$)", "gi");
alert(txt.replace(re, '$1 {$2}'));

如果不起作用,请告诉我......

【讨论】:

    【解决方案3】:

    问题

    我做错了什么?

    很遗憾,答案是您没有做错。 Javascript 是。

    问题在于 Javascript 不支持 Unicode regular expressions,因为 Unicode 标准中对此进行了说明。

    不过,有一个相当不错的库,叫做XRegExp,它有一个JavaScript plugin,它有很大帮助。我推荐它,尽管有几个值得注意的警告。您需要知道它可以做什么,以及它不能做什么。


    它的作用

    • 更正了 Javascript 实现中的各种不一致问题,包括 its split function
    • 从 2012 年 1 月起,支持 Unicode 字符数据库 6.1 版所涵盖的 BMP 代码点。
    • 根据标准,正确忽略 Unicode 属性名称中的大小写、空格、连字符减号和下划线——即使是 Java 也会出错。
    • 支持 Unicode 通用类别,例如用于字母的 \p{L} 和用于货币符号的 \p{Sc}
    • 支持标准的完整属性名称,例如\p{Letter} 用于\p{L}\p{Currency_Symbol} 用于\p{Sc}
    • 支持 Unicode 脚本属性,例如 \p{Latin}\p{Greek}\p{Common}
    • 支持 Unicode 块属性,例如 \p{InBasic_Latin}\p{InMathematical_Alphanumeric_Symbols}
    • 支持 1 级合规性所需的其他 9 个 Unicode 属性:\p{Alphabetic}\p{Uppercase}\p{Lowercase}\p{White_Space}\p{Noncharacter_Code_Point}\p{Default_Ignorable_Code_Point}\p{Any}\p{ASCII} 和 @ 987654348@.
    • 支持命名捕获而不是仅编号捕获,使用标准表示法:(?<NAME>⋯) 声明命名组,\k<NAME> 按名称反向引用它,并在替换模式中使用 ${NAME}(通常在您的代码中使用result.NAME 访问它)。这与 Perl 5.10、Java 7、.ɴᴇᴛ 和其他几种语言使用的语法相同。它允许您命名部分而不是仅对它们进行编号,从而使编写复杂的正则表达式变得更加容易,因此当您移动内容时,您不必重新计算编号变量。
    • 支持/sᴀᴋᴀ(?s) 模式,以便点匹配任何单个代码点,而不是除换行序列之外的任何内容。大多数其他正则表达式引擎都支持这种模式。
    • 支持 /x ᴀᴋᴀ (?x) 模式,以便忽略空格和 cmets(如果未转义)。大多数正则表达式引擎都支持这种模式。它对于创建清晰易读且因此可维护的模式绝对必不可少。
    • 即使不在/x 模式下也支持嵌入的 cmets,使用标准的(?#⋯) 表示法这样做(例如在 Perl 中看到的)。这让您可以将 cmets 放入单独的正则表达式片段中,而无需一直使用 /x 模式,这对于开发更复杂的模式通常很重要,因为您可以逐段构建它们。
    • 支持可扩展性,因此您可以根据需要添加新的令牌类型,例如 \a 表示 ALERT 字符或 POSIXish 字符类。

    没有什么

    但是,你应该小心它做的事情:

    • 不支持完整的 Unicode,但仅支持来自平面 0 的代码点。这是一个禁止的限制,因为 Unicode 标准要求在一个星体和非星体代码点之间没有区别正则表达式。甚至 Java 在 JDK7 之前也无法做到这一点。 (不过,v2.1.0 开发版确实支持完整的 Unicode。)
    • 不支持\X 用于字素簇,或\R 用于换行序列。
    • 不支持两部分属性,例如 \p{GC=Letter}\p{Block=Phonetic_Extensions}\p{Script=Greek}\p{Bidi_Class=Right_to_Left}\p{Word_Break=A_Letter}\p{Numeric_Value=10}
    • 它不会更新字符类快捷方式以按照UTS#18 的要求进行操作。标准 JavaScript 只允许 \s 匹配 Unicode \p{White_Space} 属性;它不允许\d 匹配\p{Nd}(尽管一些旧浏览器无论如何都会这样做!)也不允许\w 匹配[\p{Alphabetic}\pM\p{Nd}\p{Pc}],更不用说提供\b\B 的Unicode 感知版本,所有其中是支持 Unicode 正则表达式的要求的一部分。
    • 它不支持一些常用的属性。在实践中,缺少的是\p{digit},也许还有相当有用的\p{Dash}\p{Math}\p{Diacritic}\p{Quotation_Mark} 属性。
    • 不支持字素集群,例如使用\X 甚至通过(?:\p{Grapheme_Base}\p{Grapheme_Extend}*)这真是一件大事。

    解决方法

    这里有一些解决方法来处理库不遵循 Unicode 标准的一些地方:

    • 对于缺少的\w,您可以使用[\p{L}\p{Nl}\p{Nd}\p{M}\p{InEnclosedAlphanumerics}]。它仅在封闭的数字中夸大了问题,因为它们不是 \p{Nd} 类型的数字,它们是唯一算作字母数字的数字。
    • 对于缺少的\W,因此可以使用前一个的集合补码,即[^\p{L}\p{Nl}\p{Nd}\p{M}\p{InEnclosedAlphanumerics}]。它仅在所附数字中夸大了问题。
    • 由于\b(?:(?<=\w)(?!\w)|(?<!\w)(?=\w)) 完全相同,您可以\w 定义插入该序列,以创建\b 的Unicode 感知版本——前提是JavaScript 支持环视的所有四个方向,当我上次检查时,它没有。您必须同时进行正面和负面的向后看,而不仅仅是向前看,才能正确地做到这一点。 Javascript 忽略了支持这些, 至少在我看来。
    • 由于\B(?:(?<=\w)(?=\w)|(?<!\w)(?!\w)) 完全相同,您可以这样做,但条件相同。
    • 对于缺少的\X,您可以通过使用\P{M}\p{M}* 来接近,但这会错误地拆分CRLF 结构并允许在同一结构上进行标记,所有这些都是非常错误的。
    • 对于缺少的\R,您可以使用(?:\r\n|[\n-\r\u0085\u2028\u2029]) 构建解决方法。

    总结

    结论是 JavaScript 的正则表达式完全不适合 Unicode 工作。然而,the XRegExp plugin 更接近于实现这一目标。如果你能忍受它的限制,这可能比切换到另一种但支持 Unicode 的编程语言更容易。这肯定比根本无法使用 Unicode 正则表达式要好。

    然而,要满足标准中规定的 Unicode 正则表达式最基本的要求(1 级支持)还有很长的路要走。有一天,您将希望能够匹配字符,无论它们是否带有重音符号,或者在数学字母数字符号块中设置的字符,或者使用 Unicode 大小写映射和大小写折叠定义的字符,或者后面的字符Unicode 标准 用于字母数字排序或换行和分词,即使使用插件,您也无法在 Javascript 中任何做这些事情 -在。

    因此,如果您确实需要处理 Unicode,您可能希望考虑使用 符合 Unicode 标准 的语言。 Javascript 无法做到这一点。

    【讨论】:

    • 我在倒数第三段中将“Java”编辑为“JavaScript”。
    • @Tim:哎呀,嗯,是的;手指滑倒;对不起。这使它更适用,但不幸的是不再适用——这听起来倒退了。我的意思是,Java 在这方面几乎和 Javascript 一样有缺陷。不同之处在于 Java 支持二对三的 Unicode 属性(一般类别和块,在 JDK7 中,脚本),有时可以用来做需要做的事情。 Javascript(没有插件)没有。根据 Unicode 标准,两者都与 Basic Unicode Support 相差甚远。
    猜你喜欢
    • 2015-09-03
    • 1970-01-01
    • 2016-06-26
    • 2022-12-10
    • 2020-01-06
    • 1970-01-01
    • 2010-12-20
    • 2012-09-24
    • 1970-01-01
    相关资源
    最近更新 更多