我正在进行用户名验证:
if [[ "$username" =~ ^[a-z][_a-z0-9]{2,17}$ ]]; then
实际上,用户名可以包含像é、ç、à等Unicode字符。
我应该使用哪个正则表达式类来限制字符串仅为ASCII字母(a、b、c、d……z)?
您可以通过首先设置LC_ALL=C
(可能是临时的,以免影响其他内容)来实现这一点。更现代的正则表达式引擎允许使用区域设置,可以将带重音符号的字符折叠到它们的基本字符上(或者至少按顺序排列,使它们处于a
和z
之间)。
由于C语言环境只知道ASCII,因此这应该可以解决问题。
例如,请参见以下脚本:
#!/bin/bash
username=amélie_314159
for locale in '' 'C' ; do
export LC_ALL="${locale}"
printf "LC_ALL set to %-3s: '%s' is " "'$LC_ALL'" "${username}"
if [[ "${username}" =~ ^[a-z][_a-z0-9]{2,17}$ ]] ; then
echo valid
else
echo invalid
fi
done
它将输出:
LC_ALL set to '' : 'amélie_314159' is valid
LC_ALL set to 'C': 'amélie_314159' is invalid
[a-z]
直接拼写为 [abcdefghijklmnopqrstuvwxyz]
。这样就不用考虑区域设置或有趣的字符类,而且自1970年1月1日00:00:00以来,任何Shell都支持它。无论您的操作系统供应商、Shell供应商、Unix标准化过程或BOFH认为什么是炫酷的,这个方法都是未来的。
加一个额外的变量lc
,像这样:
lc=abcdefghijklmnopqrstuvwxyz
正则表达式甚至变得易读:
[$lc][_0-9$lc]{2,17}
configure
脚本所做的事情。^[abcdefghijklmnopqrstuvwxyz][_abcdefghijklmnopqrstuvwxyz0-9]{2,17}$
是一个非常丑陋的正则表达式 :-) - paxdiablo[a-z]
的语义在环境上有一个隐藏的依赖性,这让 OP 感到惊讶。使用 lc=abcdefghijklmnopqrstuvwxyz
,正则表达式变得非常易读,为 [$lc][_0-9$lc]{2,17}
。 - Jens$lc
技巧使你的解决方案更加可行,所以为此点赞。我建议将其添加到答案中而不是留在注释中。 - paxdiabloif [[ "$username" =~ ^[\x00-\x7f]{2,17}$ ]]; then
^[\x61-\x7a]$
,因为我只对 a、b、c...z 感兴趣)。不幸的是,似乎 bash 正则表达式不理解字符的 \x.. 表示法。如果你找到了让它工作的方法,那就太棒了。 - John Smith Optionaltr
来删除所有不需要的字符。当正则表达式检查跟随时,它变得更加简单。echo "abc[日本語][ひらがな][カタカナ][äüéçà]abc" | tr -dc "a-zA-Z"
这将只留下abcabc
作为余数。
a-z
的含义。而且你使用它是错误的,因为tr
不接受像[a-z]
这样的字符类,而是只将-
视为特殊字符。你的管道没有过滤掉[
和]
。 - Jens[]
进入白名单。 - Jens
LC_ALL
设置效果的原因。换句话说,只在if
语句中设置它,然后恢复默认设置。 - paxdiablo