regular expression/regex(4)Validating E-mail Address with regular expression

本文提供了一种使用正则表达式验证电子邮件地址的方法,并讨论了不同正则表达式的优缺点。
[size=medium][b]使用正则表达式验证电子邮件地址[/b][/size]

首先附加上Java编程语言和正则表达式文章(Regular Expresssion and the Java Programming Language)上用于验证电子邮件地址的代码:

/*
* Checks for invalid characters
* in email addresses
*/
public class EmailValidation {
public static void main(String[] args)
throws Exception {

String input = "@sun.com";
//Checks for email addresses starting with
//inappropriate symbols like dots or @ signs.
Pattern p = Pattern.compile("^\\.|^\\@");
Matcher m = p.matcher(input);
if (m.find())
System.err.println("Email addresses don't start" +
" with dots or @ signs.");
//Checks for email addresses that start with
//www. and prints a message if it does.
p = Pattern.compile("^www\\.");
m = p.matcher(input);
if (m.find()) {
System.out.println("Email addresses don't start" +
" with \"www.\", only web pages do.");
}
p = Pattern.compile("[^A-Za-z0-9\\.\\@_\\-~#]+");
m = p.matcher(input);
StringBuffer sb = new StringBuffer();
boolean result = m.find();
boolean deletedIllegalChars = false;

while(result) {
deletedIllegalChars = true;
m.appendReplacement(sb, "");
result = m.find();
}

// Add the last segment of input to the new String
m.appendTail(sb);

input = sb.toString();

if (deletedIllegalChars) {
System.out.println("It contained incorrect characters" +
" , such as spaces or commas.");
}
}
}
熟悉java语言的一看就知道Regular Expression and the Java Programming Language 这篇文章中主要是检查电子邮件地址中的非法字符。由于代码中注释已经很清楚了,所以下面就讲述一个直接检查正则表达式是否正确的情况。

由于现在网络域名的变更,给电子邮件地址的验证增加了负担,例如:现在有了.museum的顶级域名,它很不同于以前的顶级域名例如:.com/.cn/.org等,所以我们在书写正则表达式的时候就不能设置最后的字符长度为{2,4},而当我们把这个长度扩大之后,就又引起了另外一个问题:非法的邮件地址也被视为正确。所以有的人称这种方式为:Trade-offs(交换,协定)。以下给出一个可以验证99%的邮件地址的正则表达式:
[A-Za-z0-9._%#~-]+@[A-Za-z0-9_.-]+\.[A-Za-z]{2,4} 当然你也可以用\w替换 [A-Za-z_0-9],就变成了下面的形式:[\w\.%#~-]+@[\w.-]+\.[A-Za-z]{2,4}。当然这个例子不能匹配到.museum。 如果要包含.museum,你可以使用[\w\.%#~-]+@[\w.-]+\.[A-Za-z]{2,6}然而,现在又出现了一个问题,这个正则表达式匹配john@main.office 更多可能的是john忘记了加入.com顶级域名而不是自己创建了一个.office的顶级域名,这个域名没有得到ICANN的批准。
这样就产生了另外一个(trade-off)协定。你想要这个正则表达式去检查是否这个顶级域名存在?任何有2-4个字符的结合将要这样做,它几乎涵盖了所有现存的和计划过的顶级域名除了.museum。但是,它也匹配有违法的顶级域名像:asdf@asf.asdf。此表达式没有过度的对顶级域名进行限制。你如果想要你的正则表达式的准确率提高,你必须更新你的正则表达式只要有新的顶级域名被创建,不管这个顶级域名是国家代码或者所属于某个领域。
^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.(?:[A-Za-z]{2}|com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum)$ 这个表达式可以允许任意两个字符国家代码的顶级域名,和仅有的几个具体类别的顶级域名。在你读这篇文章的时候,可能这个表达式已经过时了。如果你使用这个正则表达式,我推荐你将它存储为你应用程序的全局常量,这样你以后只要修改这个地方就可以了。你也可以使用同样的方式列出来所有的国家代码,尽管有大约200个国家代码。
电子邮件也可能在子域的服务器上,例如:john@server.department.company.com。以上所有的正则表达式都匹配这个电子邮件,因为我包含了一个.(dot)在@符号后面的字符类里面,然而,这个正则表达式也匹配john@...com,但是这个不是有效的电子邮件,因为有连续的..(dot)。你可以在上面任意的一个正则表达式里使用(?:[A-Za-z0-9-]+\.)+ 来替代[A-Za-z0-9.-]+\.来排除上面的邮件地址。我把.(dot)从字符类里面移除来了,取而代之的是使用一个字符类后面紧跟一个.(dot)。例如:\b[A-Za-z0-9._%+-]+@(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,4}\b会匹配john@server.department.company.com而不匹配john@aol...com。
另外一个trade-off(交换,协定)是正则表达式只允许英文字体,数字和一写特殊符号。主要的原因是我不相信所有我的电子邮件软件能够处理的更过情况。尽管John.O'Hara@theoharas.com是个语义有效的电子邮件,但是有个风险就是有的软件将撇号误解析为受限的引号。例如:盲目的将电子邮件插入到SQL将会失败,因为单引号是受限的。当然,域名包含有非英文字符已经好几年了。大部分的软件甚至是域名注册者仍然使用他们习惯使用的37个字符。
结论:决定使用哪个或那种正则表达式来验证电子邮件,是否你要努力匹配一个电子邮件地址或者是一些模糊定义的地址。你需要考虑这种trade-off。匹配了一个不合法的邮件地址有多糟糕?没有去匹配一些合法的邮件有多糟糕?你的正则表达式有多么复杂?你以后要改变你的正则表达式将要花费多少成本?对于以上问题的不同的答案,你可能需要不同的正则表达式作为解决方案。
以下简单附属了官方的对于邮件规定的 RFC2822标准:
The Official Standard: RFC 2822

Maybe you're wondering why there's no "official" fool-proof regex to match email addresses. Well, there is an official definition, but it's hardly fool-proof.

The official standard is known as RFC 2822. It describes the syntax that valid email addresses must adhere to. You can (but you shouldn't--read on) implement it with this regular expression:

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

This regex has two parts: the part before the @, and the part after the @. There are two alternatives for the part before the @: it can either consist of a series of letters, digits and certain symbols, including one or more dots. However, dots may not appear consecutively or at the start or end of the email address. The other alternative requires the part before the @ to be enclosed in double quotes, allowing any string of ASCII characters between the quotes. Whitespace characters, double quotes and backslashes must be escaped with backslashes.

The part after the @ also has two alternatives. It can either be a fully qualified domain name (e.g. regular-expressions.info), or it can be a literal Internet address between square brackets. The literal Internet address can either be an IP address, or a domain-specific routing address.

The reason you shouldn't use this regex is that it only checks the basic syntax of email addresses. john@aol.com.nospam would be considered a valid email address according to RFC 2822. Obviously, this email address won't work, since there's no "nospam" top-level domain. It also doesn't guarantee your email software will be able to handle it. Not all applications support the syntax using double quotes or square brackets. In fact, RFC 2822 itself marks the notation using square brackets as obsolete.

We get a more practical implementation of RFC 2822 if we omit the syntax using double quotes and square brackets. It will still match 99.99% of all email addresses in actual use today.

[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?

A further change you could make is to allow any two-letter country code top level domain, and only specific generic top level domains. This regex filters dummy email addresses like asdf@adsf.adsf. You will need to update it as new top-level domains are added.

[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b

So even when following official standards, there are still trade-offs to be made. Don't blindly copy regular expressions from online libraries or discussion forums. Always test them on your own data and with your own applications.
<think>我们遇到了一个正则表达式错误,错误信息指出:`/[a-zA-Z0-9- ]+/v` 是无效的,因为 `v` 标志在正则表达式中无效。实际上,在JavaScript中,正则表达式标志是有限的,常用的有`g`(全局)、`i`(忽略大小写)、`m`(多行)等。而`v`标志是ECMAScript 2024中新增的标志,用于启用Unicode集合模式,但目前(2023年)大多数浏览器和Node.js版本尚未支持。 但是,错误信息中提到的正则表达式是`/[a-zA-Z0-9- ]+/v`,这里使用了`v`标志,而当前环境不支持它,所以会抛出`SyntaxError`。 ### 问题分析 在HTML的`pattern`属性中,我们通常使用正则表达式字符串(不带标志)来定义输入验证的模式。例如: ```html <input type="text" pattern="[a-zA-Z0-9- ]+"> ``` 这个正则表达式是有效的,因为它没有标志。 但是,如果错误信息中出现了`/v`,那么可能是你在JavaScript中使用了正则表达式字面量并添加了`v`标志,而当前环境不支持。 ### 解决方案 1. **检查正则表达式标志**:确保没有使用不被支持的正则表达式标志。目前,`v`标志仅在最新的JavaScript引擎中部分支持。如果你不需要Unicode集合模式,应该移除`v`标志。 2. **使用字符串作为pattern**:在HTML的`pattern`属性中,直接写正则表达式的字符串(不带两边的斜杠和标志)。例如: ```html <input pattern="[a-zA-Z0-9 -]+"> ``` 注意:在字符组中,连字符`-`如果放在字符组的中间,需要转义或者放在开头或结尾以避免被解释为范围。在上面的例子中,我们将空格和连字符放在最后,这样连字符就不需要转义。 3. **在JavaScript中创建正则表达式**:如果你在JavaScript代码中创建正则表达式,避免使用`v`标志,除非你确定目标环境支持。例如: ```javascript // 错误的,使用了v标志 const regex = /[a-zA-Z0-9- ]+/v; // 应该改为(如果需要全局匹配等,可以添加其他支持的标志) const regex = /[a-zA-Z0-9- ]+/; ``` ### 修正后的正则表达式 在HTML中: ```html <input type="text" pattern="[a-zA-Z0-9 -]+" title="只允许字母、数字、空格和连字符"> ``` 在JavaScript中(如果不需要标志): ```javascript const regex = /[a-zA-Z0-9 -]+/; ``` ### 注意字符组中的连字符 在正则表达式的字符组(`[...]`)中,连字符`-`有特殊含义,表示一个范围(如`a-z`)。如果你想匹配字面上的连字符,可以: - 将其放在字符组的开头或结尾(如`[-a-zA-Z0-9 ]`或`[a-zA-Z0-9 -]`) - 或者使用转义(如`[a-zA-Z0-9\- ]`) ### 错误原因总结 错误是因为在正则表达式中使用了不被当前环境支持的标志`v`。移除该标志即可。 §§相关问题§§ 1. 在HTML的pattern属性中使用正则表达式有哪些注意事项? 2. JavaScript中正则表达式的标志有哪些?它们的作用分别是什么? 3. 如何在正则表达式中正确匹配连字符(-)? 4. 如何检查当前JavaScript环境是否支持正则表达式的v标志? 5. 在字符组([])中,哪些字符需要转义?如何避免错误?</think>这个错误是由于在正则表达式中使用了无效的标志 `v` 导致的。让我们分析问题并提供解决方案: ### 错误原因分析 1. **无效的标志 `v`**: - JavaScript 正则表达式支持的标准标志只有 `g`(全局)、`i`(忽略大小写)、`m`(多行)、`s`(dotAll)、`u`(unicode)和 `y`(粘性) - `v` 标志是实验性特性(用于 Unicode 集合),目前**不被任何主流浏览器完全支持** 2. **错误位置**: ```html <!-- 错误示例 --> <input pattern="[a-zA-Z0-9- ]+/v"> ``` 在 HTML `pattern` 属性中,正则表达式不应包含标志符 ### 正确解决方案 #### 方案1:移除无效标志(推荐) ```html <!-- 正确用法 - 移除 /v 标志 --> <input pattern="[a-zA-Z0-9\- ]+"> ``` #### 方案2:修复字符类语法 ```html <!-- 正确用法 - 转义连字符 --> <input pattern="[a-zA-Z0-9\- ]+"> ``` #### 方案3:使用现代正则特性(需注意兼容性) ```javascript // 在JavaScript中使用unicodeSets(实验性) const regex = /[a-zA-Z0-9- ]+/v; // 注意:目前仅Chrome 120+支持 ``` ### 关键修复点 1. **HTML pattern 属性**: - 只接受正则表达式主体,**不要包含两边的 `/` 和标志符** - 错误写法:`pattern="/[a-z]+/i"` - 正确写法:`pattern="[a-z]+"` 2. **字符类注意事项**: - 连字符 `-` 在字符类中需要转义或放在开头/结尾 - 空格可以直接包含在字符类中 ### 完整示例 ```html <!-- 有效的表单验证 --> <input type="text" pattern="[\w\- ]+" title="只能包含字母、数字、连字符和空格"> ``` ### 浏览器兼容性提示 | 特性 | Chrome | Firefox | Safari | Edge | |------------------|--------|---------|--------|------| | 标准正则标志 | ✅ | ✅ | ✅ | ✅ | | `v` (unicodeSets)| 120+ | ❌ | ❌ | ❌ |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值