无法使用带有 unicode 字符的电子邮件正则表达式找到匹配项
Unable to find matches using email regular expression with unicode characters
我们有 regular expression
,它在我们的后端用于电子邮件验证:
/^((([a-z]|\d|[!#$%&'*+-/=\?\^{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#$%&'\*\+\-\/=\?\^_
{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|.||~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))).)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i
我使用在线工具对其进行了测试,工作正常:
但是,我在 swift
项目中使用它时遇到了一些困难。我不得不转义特殊字符并将所有 unicode 字符包装到 {} 中以用作 swift
字符串文字。
这里是游乐场:
import Foundation
let pattern = "/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])|(([a-z]|\d|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])([a-z]|\d|-|\.|_|~|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])*([a-z]|\d|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])))\.)+(([a-z]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])|(([a-z]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])([a-z]|\d|-|\.|_|~|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])*([a-z]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])))$/i"
extension String {
func matches(_ pattern: String) -> Bool {
do {
let internalExpression = try NSRegularExpression(pattern: pattern, options: .allowCommentsAndWhitespace)
let matches = internalExpression.matches(in: self, options: NSRegularExpression.MatchingOptions.reportCompletion, range:NSMakeRange(0, self.count))
return matches.count > 0
} catch let error {
print(error)
return false
}
}
}
let matches = "test@gmail.com".matches(pattern)
print(matches)
我尝试了不同的匹配选项,但仍然出现错误,现在我有点困惑如何进行这项工作:
The value
“/^((([a-z]|\d|[!#$%&'*+-/=\?\^{\|}~]|[ -豈-﷏ﷰ-])+(\.([a-z]|\d|[!#$%&'\*\+\-\/=\?\^_
{\|}~]|[ -豈-﷏ﷰ-])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[ -豈-﷏ﷰ-])|(\([\x01-\x09\x0b\x0c\x0d-\x7f]|[ -豈-﷏ﷰ-]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[ -豈-﷏ﷰ-])|(([a-z]|\d|[ -豈-﷏ﷰ-])([a-z]|\d|-|.||~|[ -豈-﷏ﷰ-])([a-z]|\d|[ -豈-﷏ﷰ-]))).)+(([a-z]|[ -豈-﷏ﷰ-])|(([a-z]|[ -豈-﷏ﷰ-])([a-z]|\d|-|.|_|~|[ -豈-﷏ﷰ-])([a-z]|[ -豈-﷏ﷰ-])))$/i”
is invalid.
我已经检查过类似的问题,我的问题不是关于使用哪个 regular expression
而是如何使它工作,因为我想保持一致
感谢任何帮助。
要使模式与 ICU 正则表达式引擎一起工作,您需要进行大量更改(ICU 库在 Swift/Objective-C 中提供正则表达式功能)。
- 用
\u{XXXX}
包裹 \uXXXX
是错误的,您只需要对反斜杠进行两次转义,因为 ICU 正则表达式支持 \uXXXX
符号
- 不需要转义的字符不要转义在一个字符里面class(只转义
\
、[
和]
,其他的不用转义就可以随便放在里面转义,例如 -
应该放在字符 class) 的 start/end 处
- 合并单独的字符 classes 因为它们都匹配一个字符(即
([a-c]|[e-g]|\d)
= [a-ce-g\d]
)
(\x22)
: 不需要使用捕获组来包裹单个原子,在这种情况下删除括号(当你想匹配多个序列或备选方案时需要分组)
(\x20|\x09)*
:单个字符匹配原子应该分组为一个字符class以获得更好的效率,[\x20\x09]*
你可以使用(双重转义后)
^([-a-z\d!#$%&'*+/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[-a-z\d!#$%&'*+/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|(\x22((([\x20\x09]*\x0d\x0a)?[\x20\x09]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\x20\x09]*\x0d\x0a)?[\x20\x09]+)?\x22))@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][-a-z\d._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][-a-z\d._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))$
像这样:
let str = "дима@gmail.com"
let pattern = "(?i)^([-a-z\d!#\$%&'*+/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[-a-z\d!#$%&'*+/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|(\x22((([\x20\x09]*\x0d\x0a)?[\x20\x09]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\x20\x09]*\x0d\x0a)?[\x20\x09]+)?\x22))@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][-a-z\d._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][-a-z\d._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))$"
print(str.range(of: pattern, options: .regularExpression) != nil) // => true
请注意 (?i)
为正则表达式打开不区分大小写。
我们有 regular expression
,它在我们的后端用于电子邮件验证:
/^((([a-z]|\d|[!#$%&'*+-/=\?\^
{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#$%&'\*\+\-\/=\?\^_
{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|.||~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))).)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i
我使用在线工具对其进行了测试,工作正常:
但是,我在 swift
项目中使用它时遇到了一些困难。我不得不转义特殊字符并将所有 unicode 字符包装到 {} 中以用作 swift
字符串文字。
这里是游乐场:
import Foundation
let pattern = "/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])|(([a-z]|\d|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])([a-z]|\d|-|\.|_|~|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])*([a-z]|\d|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])))\.)+(([a-z]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])|(([a-z]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])([a-z]|\d|-|\.|_|~|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])*([a-z]|[\u{00A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}])))$/i"
extension String {
func matches(_ pattern: String) -> Bool {
do {
let internalExpression = try NSRegularExpression(pattern: pattern, options: .allowCommentsAndWhitespace)
let matches = internalExpression.matches(in: self, options: NSRegularExpression.MatchingOptions.reportCompletion, range:NSMakeRange(0, self.count))
return matches.count > 0
} catch let error {
print(error)
return false
}
}
}
let matches = "test@gmail.com".matches(pattern)
print(matches)
我尝试了不同的匹配选项,但仍然出现错误,现在我有点困惑如何进行这项工作:
The value “/^((([a-z]|\d|[!#$%&'*+-/=\?\^
{\|}~]|[ -豈-﷏ﷰ-])+(\.([a-z]|\d|[!#$%&'\*\+\-\/=\?\^_
{\|}~]|[ -豈-﷏ﷰ-])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[ -豈-﷏ﷰ-])|(\([\x01-\x09\x0b\x0c\x0d-\x7f]|[ -豈-﷏ﷰ-]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[ -豈-﷏ﷰ-])|(([a-z]|\d|[ -豈-﷏ﷰ-])([a-z]|\d|-|.||~|[ -豈-﷏ﷰ-])([a-z]|\d|[ -豈-﷏ﷰ-]))).)+(([a-z]|[ -豈-﷏ﷰ-])|(([a-z]|[ -豈-﷏ﷰ-])([a-z]|\d|-|.|_|~|[ -豈-﷏ﷰ-])([a-z]|[ -豈-﷏ﷰ-])))$/i” is invalid.
我已经检查过类似的问题,我的问题不是关于使用哪个 regular expression
而是如何使它工作,因为我想保持一致
感谢任何帮助。
要使模式与 ICU 正则表达式引擎一起工作,您需要进行大量更改(ICU 库在 Swift/Objective-C 中提供正则表达式功能)。
- 用
\u{XXXX}
包裹\uXXXX
是错误的,您只需要对反斜杠进行两次转义,因为 ICU 正则表达式支持\uXXXX
符号 - 不需要转义的字符不要转义在一个字符里面class(只转义
\
、[
和]
,其他的不用转义就可以随便放在里面转义,例如-
应该放在字符 class) 的 start/end 处
- 合并单独的字符 classes 因为它们都匹配一个字符(即
([a-c]|[e-g]|\d)
=[a-ce-g\d]
) (\x22)
: 不需要使用捕获组来包裹单个原子,在这种情况下删除括号(当你想匹配多个序列或备选方案时需要分组)(\x20|\x09)*
:单个字符匹配原子应该分组为一个字符class以获得更好的效率,[\x20\x09]*
你可以使用(双重转义后)
^([-a-z\d!#$%&'*+/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[-a-z\d!#$%&'*+/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|(\x22((([\x20\x09]*\x0d\x0a)?[\x20\x09]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\x20\x09]*\x0d\x0a)?[\x20\x09]+)?\x22))@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][-a-z\d._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][-a-z\d._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))$
像这样:
let str = "дима@gmail.com"
let pattern = "(?i)^([-a-z\d!#\$%&'*+/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[-a-z\d!#$%&'*+/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|(\x22((([\x20\x09]*\x0d\x0a)?[\x20\x09]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\x20\x09]*\x0d\x0a)?[\x20\x09]+)?\x22))@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][-a-z\d._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][-a-z\d._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))$"
print(str.range(of: pattern, options: .regularExpression) != nil) // => true
请注意 (?i)
为正则表达式打开不区分大小写。