我有以下正则表达式可以很好地匹配网址:
((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+-=\\\.&]*)`
但是,它不处理没有前缀的URL,即。 stackoverflow.com 或 www.google.com 不匹配。任何人都知道如何修改这个正则表达式而不关心是否有前缀?
(((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\)))?[\w\d:#@%/;$()~_?\+-=\\\.&]*)
我添加了一个()?围绕 Vinko Vrsalovic 建议的协议,但现在正则表达式将匹配几乎任何字符串,只要它具有有效的URL字符。
我的实现是我有一个管理内容的数据库,它有一个字段,可以是纯文本,电话号码,URL或电子邮件地址。我正在寻找一种简单的方法来验证输入,以便我可以正确格式化,即。为网址/电子邮件创建锚标记,并格式化电话号码我如何在整个网站中格式化其他数字。有什么建议吗?
答案 0 :(得分:1)
以下正则表达式来自精彩的Mastering Regular Expressions书。如果您不熟悉free spacing/comments mode,我建议您熟悉它。
\b
# Match the leading part (proto://hostname, or just hostname)
(
# ftp://, http://, or https:// leading part
(ftp|https?)://[-\w]+(\.\w[-\w]*)+
|
# or, try to find a hostname with our more specific sub-expression
(?i: [a-z0-9] (?:[-a-z0-9]*[a-z0-9])? \. )+ # sub domains
# Now ending .com, etc. For these, require lowercase
(?-i: com\b
| edu\b
| biz\b
| gov\b
| in(?:t|fo)\b # .int or .info
| mil\b
| net\b
| org\b
| name\b
| coop\b
| aero\b
| museum\b
| [a-z][a-z]\b # two-letter country codes
)
)
# Allow an optional port number
( : \d+ )?
# The rest of the URL is optional, and begins with / . . .
(
/
# The rest are heuristics for what seems to work well
[^.!,?;"'<>()\[\]{}\s\x7F-\xFF]*
(?:
[.!,?]+ [^.!,?;"'<>()\[\]{}\s\x7F-\xFF]+
)*
)?
简要解释这个正则表达式(为了获得完整的解释) - URL有一个或多个以点分隔的部分,以有限的最终位列表或两个字母的国家代码(.uk .fr ... )。此外,部件可能包含任何字母数字字符或连字符' - ',但连字符可能不是部件的第一个或最后一个字符。然后可能有一个端口号,然后是其余部分。
要从网站上提取此内容,请转到http://regex.info/listing.cgi?ed=3&p=207它来自第3版的第207页。
页面上写着“版权所有©2008 Jeffrey Friedl”所以我不确定使用的条件是什么,但我希望如果你拥有这本书就可以使用它......所以我希望...我没有违反把它放在这里的规则。
答案 1 :(得分:1)
如果您阅读了网址规范(http://www.isi.edu/in-notes/rfc1738.txt)的第5部分,您会看到网址的语法至少为:
scheme ':' schemepart
其中scheme是1个或更多字符,schemepart是0或更多字符。因此,如果您没有冒号,则表示您没有URL。
那就是说,/ users /不在乎他们是否给了你一个url,对他们来说它看起来就像一个。所以这就是我的工作:
在验证之前,如果其中没有冒号,则在http://之前添加,然后通过您想要的任何验证器运行它。这会将任何合法的主机名(毕竟可能不包括域信息)转换为看起来像URL的内容。
frob -> http://frob
(几乎)主机部分的唯一规则是,如果它不包含点,则它不能以数字开头。现在,应该针对特定方案执行特定的验证,这些验证到目前为止没有给出正则表达式。但是,规范合规性可能不是您想要“验证”的。因此,对主机名部分的dns查询可能很有用,但除非您在与用户相同的上下文中使用相同的解析程序,否则它不会在所有情况下都起作用。
答案 2 :(得分:0)
你的正则表达式匹配从其中一个协议开始的所有内容,包括许多不可能存在的URL,如果你放松协议部分(使它成为可选的?)那么你将只匹配几乎所有东西,包括空字符串。
换句话说,它可以很好地匹配网址,因为它几乎匹配以http://,https://,ftp://开头的所有内容,依此类推。好吧,它也匹配ftp:\\和ms-help://,但让我们忽略它。
根据实际使用情况,这可能有意义,因为将有效域列入白名单的其他regexp方法变得不够快,但是使协议部分可选是没有意义的。
一个例子(放松协议部分):
>>> r = re.compile('(((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+)?[\w\d:#@%/;$()~_?\+-=\\\.&]*)')
>>> r.search('oompaloompa_is_not_an_ur%&%%l').groups()[0]
'oompaloompa_is_not_an_ur%&%%l' #Matches!
>>> r.search('oompaloompa_isdfjakojfsdi.sdnioknfsdjknfsdjk.fsdnjkfnsdjknfsdjk').groups()[0]
'oompaloompa_isdfjakojfsdi.sdnioknfsdjknfsdjk.fsdnjkfnsdjknfsdjk' #Matches!
>>>
鉴于您的编辑,我建议您让用户选择他添加的内容,添加枚举列,或者创建一个更简单的正则表达式,除了有效字符和一些常用域之外,还要检查至少一个点。 / p>
非常慢的第三种选择,只有在URL验证真的非常重要时才会使用,实际上是访问URL并对其执行HEAD请求,如果您找不到主机或错误,您知道它无效。对于电子邮件,您可以尝试查看MX主机是否存在并打开端口25。如果两者都失败了,它将是纯文本。 (我也不建议这样做)
答案 3 :(得分:0)
您可以将前缀部分括在括号中并匹配0或1次出现
(((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+)?
所以整个正则表达式将成为
(((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+)?[\w\d:#@%/;$()~_?\+-=\\\.&]*)
问题在于它会或多或少地匹配任何单词。例如,“test”也是匹配。
你打算在哪里使用那个正则表达式?您是要尝试验证主机名还是尝试在段落中查找主机名?
答案 4 :(得分:-2)
只需使用:
.*
即。匹配一切。
您要匹配的内容只是主机名,而不是URL(技术上)。
您无法使用任何结构来明确识别主机名。 也许你可以找到以“.com”结尾的东西但是你会错过任何.co.uk,net,.org等。
编辑:
换句话说:如果您删除了类似URL的内容以协议开头的要求,那么您将无法匹配任何内容。 取决于您使用正则表达式的内容: