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

时间:2018-09-29 15:59:38

标签: regex bash sed grep zsh

由于某种原因,我不知道为什么,也许在我的系统或大脑中某些东西不太正确,正则表达式[[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 Ë Ë F F G G H H 一世 一世 Ĵ Ĵ ķ ķ 大号 升 中号 米 ñ ñ Ø Ø P p 问 q [R [R 小号 s Ť Ť ü ü V v X X ÿ ÿ ž z

如您所见,字母“ W”和“ w”都丢失了。我是唯一一个?可能是什么原因造成的?如果是错误,我应该在哪里报告?这发生在bash和zsh中,并且发生在sed和egrep中(可能还有更多,我只测试了这两个),因此问题似乎与一般的正则表达式有关……:o 所以……发生了什么事?

  • Manjaro 17.1.12
  • XFCE 4.12
  • bash 4.4.23(1)-发行版(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:]]似乎包括所有瑞典语字母,所以我想对此感到满意。

2 个答案:

答案 0 :(得分:1)

从技术上讲,在Posix正则表达式中使用范围表达式(例如[a-z](与grep实用程序一样)仅在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与{{1}相匹配}。更改将两个字符都放在刺()后面,这意味着它不能匹配任何范围表达式。 (正则表达式范围表达式仅限于单字节代码点。)


有人建议使用previous question作为此问题的重复,但是我删除了重复标记,因为该问题的重点在于使用[u-x]的智慧,而不是可能的实现错误,并且因为关于Perl正则表达式,而不是Posix正则表达式。但是,答案中有很多有用的信息。

答案 1 :(得分:0)

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

我发现正在编辑

/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

让事情变得更好...