正则表达式 [A-Za-z] 似乎不包括字母 W 和 w

use*_*179 3 regex bash grep zsh sed

出于某种原因,我不知道为什么,也许是我的系统或我的大脑中有些不对劲,正则表达式“[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
Run Code Online (Sandbox Code Playgroud)

我的输出是: A a B b C c D d E e F f G g H h I i J j K L l M m N n O o P p Q q R r S s T t U u V v X x y y z z

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

  • 曼扎罗 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=
Run Code Online (Sandbox Code Playgroud)

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

ric*_*ici 6

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

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

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

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

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

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


一个先前的问题已经被认为是这个问题的一个副本,但我删除重复的标记,因为这个问题,侧重于使用的智慧[a-z],而不是可能实现的错误,而且因为是约Perl的正则表达式,而不是Posix的正则表达式。但是,答案中有很多有用的信息。