我正在使用 Python 中的正则表达式从文本中提取 URL 的部分。我正在寻找的 URL 来自一组有限的模式,因此感觉我应该能够在正则表达式中处理它们。我试图提取的是文件名的第一部分(下面所有示例中的“some.file.name”),其中可以包含点、字母和数字。
URL 可以采用以下几种形式:
http://www.example.com/some.file.name.html
http://www.example.com/some.file.name_foo.html
http://www.example.com/some.file.name(123).html
http://www.example.com/some.file.name_foo(123).html
http://www.example.com/some.file.name
http://www.example.com/some.file.name_foo
http://www.example.com/some.file.name(123)
http://www.example.com/some.file.name_foo(123)
我想我对这个正则表达式已经很满意了:
http://www\.example\.com/([a-zA-Z0-9\.]+)(_[a-z]+)?(\(\d+\))?(\.html)?
但是当 URL 类似于列表中的第一个 URL 时,它会在匹配中包含“.html”。有什么方法可以阻止这种情况,或者这是正则表达式的基本限制吗?
我很高兴在代码中删除扩展名,因为它始终是相同的,并且作为文件名的一部分永远不会有效,但将其作为正则表达式匹配的一部分会更干净。
编辑:
我要强调的是,这些 URL 位于文本正文中。我无法保证它们之前或之后是否有字符或者这些字符可能是什么。我认为可以安全地假设它们不是数字、字母、下划线或点。
正则表达式默认匹配greedy。
尝试这个正则表达式:
^http://www\.example\.com/([a-zA-Z0-9\.]+?)(_[a-z]+)?(\(\d+\))?(\.html)?$
注意添加了额外的
?
,以不捕获第一部分中的 .html
。它使第一组捕获尽可能少地匹配,而不是尽可能多地匹配。如果没有 ?
,.html
将包含在第一组中,因为其他组是可选的,贪婪匹配会尝试尽可能“早”地匹配。
附注另请注意,我使用
^
和 $
锚定正则表达式以始终匹配整行。
您可以将 .html 扩展名指定为非捕获组:
http://www\.example\.com/([a-zA-Z0-9\.]+)(_[a-z]+)?(\(\d+\))?(?=(\.html)?)
在我看来,您并不关心文件扩展名。您只想提取文件名。
试试这个:
http://www\.example\.com/([\w]+.[\w]+.[\w()]+)
在 PHP 中,我使用了 preg_match_all($regex, $str, $matches),它返回了类似这样的内容。
Array
(
[0] => Array
(
[0] => http://www.example.com/some.file.name
[1] => http://www.example.com/some.file.name_foo
[2] => http://www.example.com/some.file.name(123)
[3] => http://www.example.com/some.file.name_foo(123)
[4] => http://www.example.com/some.file.name
[5] => http://www.example.com/some.file.name_foo
[6] => http://www.example.com/some.file.name(123)
[7] => http://www.example.com/some.file.name_foo(123)
)
[1] => Array
(
[0] => some.file.name
[1] => some.file.name_foo
[2] => some.file.name(123)
[3] => some.file.name_foo(123)
[4] => some.file.name
[5] => some.file.name_foo
[6] => some.file.name(123)
[7] => some.file.name_foo(123)
)
)
希望有帮助!
更通用的匹配,其中文件名及其扩展名可以是 anything:
^(.+?)(\.[a-zA-Z0-9_]*)?$
此非贪婪匹配至少一个字符,然后在名称末尾之前找到一个句点 (
.
) 和零个或多个字母、数字或下划线(即扩展名中允许的任何字符)。
使用所有可能的文件名/扩展名情况测试输入:
name.txt
name.tar.gz
.hidden
period.
plain name
第一个匹配子串的输出:
name
name.tar
.hidden
period
plain name
然而,“.hidden”文件是否是扩展名是值得怀疑的。如果您想将其视为名称
如果您想在扩展名中允许任何字符(当然,句点和空格除外),请改用:
^(.+?)(\.[^ .]*)?$