【问题标题】:Regular expression [A-Za-z] seems to not include letter W and w正则表达式 [A-Za-z] 似乎不包括字母 W 和 w
【发布时间】:2019-03-05 07:45:33
【问题描述】:

出于某种原因,我不知道为什么,可能是我的系统或大脑中有些地方不太对劲,正则表达式“[AZ]”似乎无法识别字母“W”和“ [az]" 似乎无法识别字母“w”。示例:

for x in A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z; do echo $x | egrep "[A-Za-z]"; done

我的输出是: 一种 一种 乙 b C C D d 乙 e F F G G H H 一世 一世 Ĵ j ķ ķ 大号 l 米 米 ñ n ○ ○ 磷 p 问 q R r 小号 s 吨 吨 ü 你 五 v X X 是 是的 Z z

如您所见,字母“W”和“w”都不见了。我是唯一一个?什么可能导致这种情况?如果是错误,我在哪里报告?这发生在 bash 和 zsh 中,它发生在 sed 和 egrep 中(可能更多,我只测试了这两个),所以问题似乎与一般的正则表达式有关......:o 那么……这是怎么回事??

  • Manjaro 17.1.12
  • XFCE 4.12
  • bash 4.4.23(1)-release (x86_64-unknown-linux-gnu)
  • zsh 5.5.1 (x86_64-unknown-linux-gnu)
  • egrep 3.1
  • sed 4.5

编辑:有人问我的语言环境,所以在这里。

$ locale        
LANG=sv_SE.utf8
LC_CTYPE="sv_SE.utf8"
LC_NUMERIC=sv_SE.UTF-8
LC_TIME=sv_SE.UTF-8
LC_COLLATE="sv_SE.utf8"
LC_MONETARY=sv_SE.UTF-8
LC_MESSAGES="sv_SE.utf8"
LC_PAPER=sv_SE.UTF-8
LC_NAME=sv_SE.UTF-8
LC_ADDRESS=sv_SE.UTF-8
LC_TELEPHONE=sv_SE.UTF-8
LC_MEASUREMENT=sv_SE.UTF-8
LC_IDENTIFICATION=sv_SE.UTF-8
LC_ALL=

如果这是问题所在,那么我猜任何决定 sv_SE.UTF-8 是什么的东西都是错误的,因为字母“w”在 2006 年被添加到瑞典字母表中。 此外,如果 A-Z 间隔取决于当前语言环境,那么当语言环境设置为瑞典语时,[A-Ö] 是否应该适用于整个瑞典语字母表?它没有,它给出了一个错误信息。但是 [[:alpha:]] 似乎包括所有瑞典字母,所以我想我对此很满意。

【问题讨论】:

  • 您的语言环境是什么?这不是由 shell 完成的,而是由平台的标准 C 库完成的。无论如何,字符排序顺序和类别区域设置运行时配置(LC_CTYPELC_COLLATE 和其他变量,如可以覆盖这些的 LC_ALL)与调试相关(不,必要)。
  • ...如果您使用的系统配置的语言不包括 W 在其字母表中,那么您就是。请将locale 命令的输出编辑成您的问题。
  • 顺便说一句,[A-Za-z] 无论如何都是不好的形式(并且建议您使用它的“教学资源”不应该被信任);使用[[:upper:]] 代替[A-Z][[:lower:]] 代替[a-z],或[[:alpha:]] 用于两者,否则使用AaBb...Zz 代替A..Za..z 的排序规则会搞砸你。
  • (因为这都是标准 C 库功能,它更像是一个通用的 UNIX 问题,而不是一个专门关于 sedgrep 或诸如此类的问题;它们都调用相同的共享库代码正则表达式或 fnmatch 模式/glob 支持)。
  • @Charles:确实 [[:alpha:]] 通常比 [A-Za-z] 更好,值得指出这一点。但是,我们不要忘记 glibc 中存在错误的事实,这里。正则表达式[u-x] 应该匹配vw,即使是瑞典语也是如此。但事实并非如此。但是,w 确实排序正确,并且确实以正确的 ctype 显示。

标签: regex bash sed grep zsh


【解决方案1】:

从技术上讲,在 Posix 正则表达式(与 grep 实用程序一样)中使用诸如 [a-z] 之类的范围表达式仅在 Posix (C) 语言环境中具有指定的行为。这意味着您确实无法在 sv_SE 语言环境(或任何其他国际化语言环境)中可靠地使用范围表达式。但是,您可以可靠地使用字符类,例如 [[:lower:]][[:alpha:]][[:alnum:]] 等,这通常是您应该做的。

话虽如此,我相信您遇到的确实是 v2.28 中引入的 glibc 中的一个错误,因为以前版本的 sv_SE 语言环境正确地将 w 放置在小写范围内,并将 W 放置在大写范围。我认为该更改不符合用户的期望,因为它会破坏以前尽管具有未指定行为但仍按预期工作的正则表达式范围表达式。

大约一个月前,该问题被报告为 glibc 错误,并且由于缺乏文档而几乎立即关闭;昨天,我requested that it be reopened。 (更新:该错误被重新认定为另一个错误的副本,其最终解决方案只能是对底层设计问题的全面解决方案。换句话说,glibc 团队了解存在问题,但不要不要屏住呼吸寻求解决方案。)

我已经在this repository 中放置了一个可能的替换sv_SE 语言环境定义文件,以防它被证明对某人有用。请不要安装它,除非您遇到 glibc 的语言环境定义问题。

我在上面链接的错误报告中的过长评论试图列出问题,这更多的是定义问题而不是实现问题。根本问题是很难(如果不是不可能的话)定义一个与整个字符串比较顺序完全一致的单字符排序顺序。阅读 Posix 基本原理文档中的字里行间,似乎很明显,很多人都把头撞在这堵特殊的砖墙上,却没有设法提出一个具有实施共识的实用可移植提案。 (“如上所述,已努力解决这些差异,但尚未找到足够具体的解决方案以允许可移植软件同时不会使现有实现无效。”)

对各种语言环境定义文件的善意清理导致瑞典语言环境中的字符顺序发生了变化。它没有改变字符串排序顺序,因此VW 继续像以前一样排序(也就是说,就好像它们是同一个字母而不是不同字母的不同拼写),它没有改变CTYPE 定义,所以Ww 仍然是字母(因此匹配[[:alpha:]]),就像以前一样。但它确实(我相信是偶然的)改变了字符顺序。之前,W 跟在 V 后面,w 跟在 v 后面,所以 W 匹配 [U-X]w 匹配 [u-x]。更改将两个字符放在 thorn (þ) 之后,这意味着它不能匹配任何范围表达式。 (正则表达式范围表达式仅限于单字节代码点。)


有人建议将previous question 作为此问题的副本,但我删除了重复标记,因为该问题侧重于使用[a-z] 的智慧,而不是可能的实现错误,还因为它与Perl 正则表达式有关而不是 Posix 正则表达式。但是,答案中有很多有用的信息。

【讨论】:

    【解决方案2】:

    不建议将其作为“最终解决方案”,但可能会以某种方式帮助某人...

    我发现编辑

    /usr/share/i18n/locales/sv_SE

    并注释掉本节中的最后两行解决了这个问题。

    % The letter w is normally not present in the Swedish alphabet. It
    % exists in some names in Swedish and foreign words, but is accounted
    % for as a variant of 'v'.  Words and names with 'w' are in Swedish
    % ordered alphabetically among the words and names with 'v'. If two
    % words or names are only to be distinguished by 'v' or % 'w', 'v' is
    % placed before 'w'.
    
    % &v<<<V<<w<<<W
    %<U0057> <S0076>;"<BASE><VRNT1>";"<CAP><MIN>";IGNORE % W
    %<U0077> <S0076>;"<BASE><VRNT1>";"<MIN><MIN>";IGNORE % w
    

    然后重新生成语言环境

    sudo locale-gen

    让事情变得更好......

    【讨论】:

    • 该文件中的 cmets 不再正确。自 2006 年以来,字母 w 成为瑞典字母表的一部分,并在 v 和 x 之间排序,就像在英语和许多其他语言中一样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    • 2019-09-06
    • 1970-01-01
    • 2011-06-22
    • 1970-01-01
    • 2012-12-31
    相关资源
    最近更新 更多