我希望我的域名不包含多个连续(.)
的'/'
或任何其他特殊字符。但它可以包含 IDN 字符,例如Á, ś, etc..
. 我可以通过使用这个正则表达式来满足所有要求(IDN 除外):
@"^(?:[a-zA-Z0-9][a-zA-Z0-9-_]*\.)+[a-zA-Z0-9]{2,}$";
问题是这个正则表达式也拒绝 IDN 字符。我想要一个允许 IDN 字符的正则表达式。我做了很多研究,但我无法弄清楚。
Regex 包含一个允许您指定 Unicode 通用类别的字符类\p{}
。MSDN 正则表达式文档包含以下内容:
\p{ name }
匹配 Unicode 通用类别或由名称指定的命名块中的任何单个字符。
另外,作为旁注,我注意到您的正则表达式包含未转义的.
. 在正则表达式中,点字符.
具有任何字符的特殊含义(换行符除外,除非另有说明)。您可能需要更改它\.
以确保正确的功能。
编辑现有代码以包含 Unicode 字符类而不是简单的 ASCII 字母,您应该获得以下结果:
^(?:[\p{L}\p{N}][\p{L}\p{N}-_]*.)+[\p{L}\p{N}]{2,}$
\p{L}
表示任何语言/脚本中任何字母的 Unicode 字符类\p{N}
表示任何语言/脚本中任何数字的 Unicode 字符类(根据您的字符示例,您可能可以保留0-9
,但我想我会向您展示一般概念并为您提供一些额外的信息)该站点对最常用的 Unicode 类别进行了快速和一般的概述。
\p{L}
或\p{Letter}
:任何语言的任何类型的字母。
\p{Ll}
或\p{Lowercase_Letter}
:具有大写变体的小写字母。\p{Lu}
或\p{Uppercase_Letter}
:具有小写变体的大写字母。\p{Lt}
或\p{Titlecase_Letter}
:出现在单词开头的字母,仅单词的第一个字母大写。\p{L&}
or\p{Cased_Letter}
:以小写和大写变体形式存在的字母(Ll、Lu 和 Lt 的组合)。\p{Lm}
or\p{Modifier_Letter}
: 一个像字母一样使用的特殊字符。\p{Lo}
or\p{Other_Letter}
:没有小写和大写变体的字母或表意文字。\p{M}
or\p{Mark}
: 一个要与另一个字符组合的字符(例如重音符号、变音符号、封闭框等)。
\p{Mn}
or\p{Non_Spacing_Mark}
: 一个旨在与另一个字符组合而不占用额外空间的字符(例如重音符号、变音符号等)。\p{Mc}
或\p{Spacing_Combining_Mark}
: 用于与占用额外空间的另一个字符组合的字符(许多东方语言中的元音符号)。\p{Me}
or\p{Enclosing_Mark}
: 包含字符的字符与(圆形、方形、键帽等)组合。\p{Z}
or\p{Separator}
: 任何类型的空格或不可见的分隔符。
\p{Zs}
or\p{Space_Separator}
:一个不可见的空白字符,但确实占用空间。\p{Zl}
或\p{Line_Separator}
:行分隔符 U+2028。\p{Zp}
或\p{Paragraph_Separator}
:段落分隔符 U+2029。\p{S}
或\p{Symbol}
:数学符号、货币符号、装饰符号、画框字符等。
\p{Sm}
或\p{Math_Symbol}
:任何数学符号。\p{Sc}
或\p{Currency_Symbol}
:任何货币符号。\p{Sk}
or\p{Modifier_Symbol}
: 一个组合字符(标记)作为一个完整的字符。\p{So}
or\p{Other_Symbol}
: 不是数学符号、货币符号或组合字符的各种符号。\p{N}
或\p{Number}
:任何脚本中的任何类型的数字字符。
\p{Nd}
或\p{Decimal_Digit_Number}
:除表意文字外的任何文字中的数字 0 到 9。\p{Nl}
or\p{Letter_Number}
: 一个看起来像字母的数字,例如罗马数字。\p{No}
or\p{Other_Number}
:上标或下标数字,或不是数字 0-9 的数字(不包括表意文字中的数字)。\p{P}
或\p{Punctuation}
:任何类型的标点符号。
\p{Pd}
or\p{Dash_Punctuation}
: 任何类型的连字符或破折号。\p{Ps}
或\p{Open_Punctuation}
:任何类型的左括号。\p{Pe}
或\p{Close_Punctuation}
:任何类型的右括号。\p{Pi}
或\p{Initial_Punctuation}
:任何类型的开场白。\p{Pf}
或\p{Final_Punctuation}
:任何类型的结束语。\p{Pc}
或\p{Connector_Punctuation}
: 一个标点符号,例如连接单词的下划线。\p{Po}
or\p{Other_Punctuation}
: 任何不是破折号、括号、引号或连接符的标点符号。\p{C}
或\p{Other}
:不可见的控制字符和未使用的代码点。
\p{Cc}
或\p{Control}
:ASCII 或 Latin-1 控制字符:0x00–0x1F 和 0x7F–0x9F。\p{Cf}
或\p{Format}
:不可见的格式指示器。\p{Co}
或\p{Private_Use}
:保留供私人使用的任何代码点。\p{Cs}
or\p{Surrogate}
: UTF-16 编码的代理对的一半。\p{Cn}
或\p{Unassigned}
:任何未分配字符的代码点。
这个问题不能用允许各种 Unicode 字符类的简单正则表达式来回答,因为IDN 字符分类定义了许多非法字符并且还有其他限制。
AFAIK,IDN 域名以 xn-- 开头。这种方式在域名中启用了扩展的 UTF-8 字符,例如大众汽车.cn 是一个有效的域名(中文为大众汽车)。要使用正则表达式验证此域名,您需要让http://xn--3oq18vl8pn36a.cn/(大众汽车的 ACE 等效项)通过。
为此,您需要使用GNU Libidn(或任何其他实现 IDNA 的库)、Doc / PDF将域名编码为ASCII 兼容编码(ACE) 。
Libidn 带有一个名为的 CLI 工具idn
,它允许您将 UTF-8 中的主机名转换为 ACE 编码。然后可以将生成的字符串用作 ACE 编码的 UTF-8 URL 等价物。
$ idn --quiet -a 大众汽车.cn
xn--3oq18vl8pn36a.cn
受paka和timgws的启发,我建议使用以下正则表达式,它应该涵盖大多数领域:
^(?!-)(xn--)?[a-zA-Z0-9][a-zA-Z0-9-_]{0,61}[a-zA-Z0-9]{0,1}\.(?!-)(xn--)?([a-zA-Z0-9\-]{1,50}|[a-zA-Z0-9-]{1,30}\.[a-zA-Z]{2,})$
以下是一些示例:
#Valid
xn-fsqu00a.xn-0zwm56d
xn-fsqu00a.xn--vermgensberatung-pwb
xn--stackoverflow.com
stackoverflow.xn--com
stackoverflow.co.uk
google.com.au
i.oh1.me
wow.british-library.uk
xn--stackoverflow.com
stackoverflow.xn--com
stackoverflow.co.uk
0-0O_.COM
a.net
0-0O.COM
0-OZ.CO.uk
0-TENSION.COM.br
0-WH-AO14-0.COM-com.net
a-1234567890-1234567890-1234567890-1234567890-1234567890-1234-z.eu.us
#Invalid
-0-0O.COM
0-0O.-COM
-a.dot
a-1234567890-1234567890-1234567890-1234567890-1234567890-12345-z.eu.us
可视化
一些有用的链接 *顶级域 - 委托字符串 *国际化域名 (IDN) 常见问题解答 * Oracle 国际语言环境指南中的国际化域名支持页面
如果您想改用 Unicode 字符类 \p{},则应使用IDN 常见问题解答中指定的以下内容:
[ \P{Changes_When_NFKC_Casefolded}
- \p{c} - \p{z}
- \p{s} - \p{p} - \p{nl} - \p{no} - \p{me}
- \p{HST=L} - \p{HST=V} - \p{HST=V}
- \p{block=Combining_Diacritical_Marks_For_Symbols}
- \p{block=Musical_Symbols}
- \p{block=Ancient_Greek_Musical_Notation}
- [\u0640 \u07FA \u302E \u302F \u3031-\u3035 \u303B]
+ [\u00B7 \u0375 \u05F3 \u05F4 \u30FB]
+ [\u002D \u06FD \u06FE \u0F0B \u3007]
+ [\u00DF \u03C2]
+ \p{JoinControl}]
另请参阅:Perl Unicode 属性