Regex 验证字符串是否仅包含ASCII字符和数字

Regex 验证字符串是否仅包含ASCII字符和数字,regex,bash,Regex,Bash,我这样做是为了验证用户名: if [[ "$username" =~ ^[a-z][_a-z0-9]{2,17}$ ]]; then 但实际上,一个包含unicode字符的用户名,如é、ç、ç等。。。被接受。 我应该使用哪个正则表达式类将字符串限制为ascii字母(a、b、c、d…z)?您应该能够通过首先设置LC_ALL=c来实现这一点(可能是暂时的,以便不影响任何其他内容)。更现代的正则表达式引擎允许将重音字符折叠到基本字符上的区域设置(或者至少对它们进行排序,使它们介于a和z之间) 因为C

我这样做是为了验证用户名:

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
使用以下命令:

if [[ "$username" =~ ^[\x00-\x7f]{2,17}$ ]]; then

在使用正则表达式检查用户名是否具有正确的长度等之前,应清理输入字符串。这意味着你不应该把不允许的东西列入黑名单,而应该把实际允许的东西列入白名单。在这种情况下,我们将在实际正则表达式之前使用例如
tr
,预先删除所有不需要的字符。当正则表达式检查紧随其后时,它就变得简单多了

echo "abc[日本語][ひらがな][カタカナ][äüéçà]abc" | tr -dc "a-zA-Z"
这只会将
abcabc
保留为余数。

方法是简单地将
[a-z]
拼写为
[abcdefghijklmnopqrstuvxyz]
。那里自1970年1月1日00:00:00以来,任何shell都支持不干扰区域设置或有趣的角色类。无论您的操作系统供应商、shell供应商、Unix标准化过程或BOFH认为什么很酷,都是经得起未来考验的

使用一个额外变量
lc
like

lc=abcdefghijklmnopqrstuvwxyz
正则表达式甚至变得可读:

[$lc][_0-9$lc]{2,17}

这就是高度健壮和可移植的
configure
脚本所做的。

防弹,直到您不再假设地球上的每个人都有一个英文名字,并且您希望允许使用非拉丁字符为止。只是开玩笑,它回答了这个问题,但无论如何,
^[abcdefghijklmnopqrstuvwxyz][[u abcdefghijklmnopqrstuvwxyz-9]{2,17}$
是一个非常难看的正则表达式:-)难看的是
[a-z]
的语义对环境有一个隐藏的依赖,这让OP大吃一惊。通过
lc=abcdefghijklmnopqrstuvwxyz
正则表达式变得非常可读
[$lc][\u0-9$lc]{2,17}
。好吧,只有在你没有很多国际化和本地化经验的情况下,正则表达式才会隐藏起来,但我在一家必须将其产品运送到许多不同国家的公司工作时具有这一优势。但是您的
$lc
技巧使您的解决方案更加可行,因此+1就可以了。我建议在答案中加入这一点,而不是在评论中留下它。我现在将使用这个解决方案。这可能是“丑陋的”,但它是明确的,我相信我仍然会理解如何从现在起几年的脚本工作。你说得对:丑陋的是[a-z]的语义。我可能会将你的答案标记为已接受,但我会等上几个小时,以防有人找到我们目前没有想到的解决方案。@johnmithoptional明确、自我记录、未来证明:一句话:优雅!我仍然希望字符串被视为unicode字符串,特别是在脚本的其余部分。我也不确定将LC_ALL设置为“C”的其他效果是什么。@JohnSmithOptional,这就是为什么我说应该将
LC_ALL
设置的效果本地化。换句话说,只为
if
语句设置它,然后将其还原。我真的希望能够这样做(或者更准确地说,
^[\x61-\x7a]$
因为我只对a、b、c..、z感兴趣。不幸的是,bash正则表达式似乎不理解字符的\x..表示法。但是,如果你找到一种方法使其工作,那将是非常棒的。这可能是原始正则表达式的所有问题,也就是说,
a-z
的含义依赖于区域设置。你是u唱错了,因为
tr
不接受像“[a-z]”这样的字符类,而是设置只有
-
特殊的位置。你的管道不会过滤掉
[
]
。感谢带括号的tipp,搞错了(修复)。不幸的是,您认为这不起作用的评论是错误的。请参见编辑。好吧,它只将字母列为白名单是错误的,因为它还将
[]
列为白名单。