考虑以下示例:
$ bash --version
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ LC_COLLATE=C bash --norc -c '[[ B == [a-z] ]] && echo yes || echo no'
no
$ LC_COLLATE=en_GB bash --norc -c '[[ B == [a-z] ]] && echo yes || echo no'
yes
$ LC_COLLATE=C bash --norc -c '[[ B =~ [a-z] ]] && echo yes || echo no'
no
$ LC_COLLATE=en_GB bash --norc -c '[[ B =~ [a-z] ]] && echo yes || echo no'
no
似乎在匹配时图案(即使用=
or ==
),Bash 根据 LC_COLLATE 进行整理;然而,当与正则表达式匹配时(即使用=~
),Bash 根据 POSIX 或类似的东西进行整理。
Zsh——至少——在所有情况下zsh 5.8.0.2-dev (x86_64-pc-linux-gnu)
都会打印。no
[a-z]
在模式或正则表达式中使用时,是否能保证准确匹配的内容?
答案1
不,不能保证到底[a-z]
会匹配什么,就这样。
好吧,在任何其他语言环境中"C"
(当实用程序符合 POSIX 时)。
核心问题在于“范围”表达式(使用-
)。
像这样的明确列表[abcdefghijklmnopqrstuvwxyz]
永远不会失败。
POSIX 请求正是a-z
,abcdefghijklmnopqrstvwxyz
是的,但仅当区域设置是 POSIX 默认值时,即:"C"
。
来自 POSIX 规范:
在 POSIX 语言环境中,范围表达式表示位于排序规则序列中两个元素之间(包括这两个元素)的排序元素集。在其他语言环境中,范围表达式具有未指定的行为:严格遵守的应用程序不应依赖于范围表达式是否有效,或匹配的整理元素集。范围表达式应表示为用('-')分隔的起点和终点。
即使 POSIX 请求特定含义,a-z
任何应用程序也可能选择简单地忽略 POSIX。
只是为了展示冰山一角:
Python 2.7 仅匹配 ASCII,a-z
但 Python 3.0 将匹配许多其他 Unicode 字符。 Bash 过去仅匹配 3.2 版之前的 ASCII。然后它决定匹配的字符整理a
和之间,在应用的区域设置中z
可能包括A-Y
(通常不包括)。Z
现在,在 bash 版本 5.0+ 中,可以使用 globasciiranges 选项来配置范围,该选项是在默认情况下,使a-z
意图匹配大多ASCII 字符。
$ LC_COLLATE=en_GB bash -c 'shopt -u globasciiranges; [[ B == [a-z] ]] && echo yes || echo no'
yes
$ LC_COLLATE=en_GB bash -c 'shopt -s globasciiranges; [[ B == [a-z] ]] && echo yes || echo no'
no
但即使 bash 5.0 和 globasciiranges 处于活动状态,也== [a-z]
将匹配 en_GB.utf-8 语言环境中的 2190 个字符。仅供您理解,这是a
允许的类似字符的列表:
a a ͣ ⒜