【问题标题】:Using Python regex to ignore `:` from string使用 Python 正则表达式忽略字符串中的 `:`
【发布时间】:2018-09-21 22:47:34
【问题描述】:

我是regex. 世界的新手,因此,如果这听起来很简单,我很抱歉。我已阅读完 regex 社区和 Lopez 关于 Mastering regex for Python 的书,以确保我不会发布初学者级别的问题。

我已经从 wiki 中抓取数据(用于学习),我正在尝试提取字符串

a) 以\wiki 开头的

b) 不包含:

这是正文:

/wiki/Template:Kevin_Bacon
/wiki/Category:Best_Miniseries_or_Television_Movie_Actor_Golden_Globe_winners
/wiki/Al_Pacino
/wiki/Paul_Giamatti
/wiki/Kevin_Costner
/wiki/Kevin_Costner
/wiki/Michael_Douglas
/wiki/Mark_Ruffalo
/wiki/Idris_Elba
/wiki/Bryan_Cranston
/wiki/Alexander_Skarsg%C3%A5rd
/wiki/Biblioteca_Nacional_de_Espa%C3%B1a
/wiki/Template:Kevin_Bacon
https://hy.wikipedia.org/wiki/%D5%94%D6%87%D5%AB%D5%B6_%D4%B2%D5%A5%D5%B5%D6%84%D5%B8%D5%B6

输出必须分组,即我应该得到这些字符串的列表(或元组):

/wiki/Al_Pacino
/wiki/Paul_Giamatti
/wiki/Kevin_Costner
/wiki/Kevin_Costner
/wiki/Michael_Douglas
/wiki/Mark_Ruffalo
/wiki/Idris_Elba
/wiki/Bryan_Cranston
/wiki/Alexander_Skarsg%C3%A5rd
/wiki/Biblioteca_Nacional_de_Espa%C3%B1a

这是我提取字符串的尝试:

a) 使用负前瞻: 这个想法是不选择后面跟着:的字符串 r^/wiki/.*(?!:).* 但是,上面的代码仍然选择带有: 的字符串,即/wiki/Template:Kevin_Bacon

b) 强制正则表达式不选择 : ^/wiki/.*[^:].* 但是,上面的代码仍然选择带有: 的字符串,即/wiki/Template:Kevin_Bacon

c) 使用量词指定: 应该出现零次 ^/wiki/.*:{0}.*$ 但是,上面的代码仍然选择带有: 的字符串,即/wiki/Template:Kevin_Bacon

我有两个问题:

a) 我真的很喜欢regex。有人可以解释一下上述尝试有什么问题吗?

b) 如何使用上述方法解决问题?

我将在 python 中使用regex 模块。根据 SO 的指导方针,我尝试在 regex101 网站上调试 regex。这是链接:https://regex101.com/r/Wt40Cz/1

我真诚地感谢任何帮助。提前致谢。

【问题讨论】:

  • 试试^\/wiki\/[^:]+?$
  • 非常感谢。您介意解释一下为什么在“冒号排除”之前和之后删除了.*,即[^:]。我正在努力学习逻辑。提前致谢。
  • @ZaphoOxx 不,你没有
  • @Zapho:我不这么认为,因为我在 python 中使用原始字符串表示法:r" "
  • @watchtower:当您尝试匹配正则表达式时,它会尝试以任何方式匹配输入文本。这个 .* 在你的正则表达式中实际上也匹配 : 因为哪些行也被选中了 : 。您只需要稍微更正您的正则表达式,就像已经说过的 ran_0315 并将其修改为 ^/wiki/[^:]+$ 这将匹配 /wiki/ 后跟任何字符,除了 : 它在 /wiki/ 之后找到一个 : 的那一刻拒绝输入文本

标签: python regex


【解决方案1】:

你的正则表达式是错误的。

^/wiki/.*[^:].*

解析如下:

  • ^:匹配行首
  • /wiki/:匹配文字序列/wiki/
  • .*:匹配零个或多个任意字符
  • [^:]:匹配任何不是:
  • .*:匹配零个或多个任意字符

原来如此

  1. 匹配行首(ok)
  2. 匹配文字/wiki/ (ok)
  3. 匹配整个行的其余部分(呃-哦)
  4. 回溯一个字符并匹配“任何不是:”的字符,只要最后一个字符不是:(嗯...)
  5. 不匹配任何字符,即零个或多个任意字符

因此,由于.*,您的正则表达式最终匹配​​整行,甚至从不检查:,除非在末尾。

现在看看正确的表达方式是什么

^\/wiki\/[^:]+$
  • ^:匹配行首
  • /wiki/:匹配文字序列/wiki/
  • [^:]+:匹配一个或多个不是:
  • $: 匹配行尾

    1. 匹配行首(ok)
    2. 匹配文字/wiki/ (ok)
    3. 匹配整行的其余部分,除非它包含:,在这种情况下它会失败
    4. 匹配行尾

希望这可以帮助您更好地分解事物。我强烈推荐 https://www.regex101.com 来构建和测试正则表达式(它具有与 Python 兼容的正则表达式模式),因为它还包括对正则表达式引擎的逐步解释。

编辑:回答你的第二个问题,我没有看到另一种合理的方式来构建这个表达式。不要使用前瞻或量词,这不是它的用途。

【讨论】:

  • 非常感谢。我为此花费了令人尴尬的时间。我有一个澄清:是不是.* 将匹配0 or more 字符直到它命中[^:],它会回溯并完全排除该字符串?我不明白你的子弹#3。如果你说的是真的,它不应该选择带有:的字符串。从我发布的regex101 链接,这没有发生。非常感谢您的想法。
  • @watchtower 它匹配整个行的其余部分,因为它贪婪地匹配“零个或多个字符”。这显然是该行的其余部分!它仅在无法匹配其他任何内容后才尝试回溯。见here
  • Shadowtalker :感谢分享链接。这非常有帮助。如果你不介意,我有一个后续问题:从文章中学习,我将我的查询修改为^/wiki/.*?[^:]$。这个想法是,在找到wiki 之后,我们会进行惰性匹配,直到找不到:,即我忽略了wiki: 之间的任何字母。但是,这也不起作用。有什么想法吗?我个人学到了很多东西,非常感谢您的帮助。
  • @watchtower 我建议单步执行regex101.com 处的表达式,看看会发生什么
【解决方案2】:

试试正则表达式^\/wiki\/[^:]*?$

它将匹配以/wiki/开头的字符串,然后这个[^:]*?将匹配没有:的字符直到结尾$

在您的正则表达式 ^/wiki/.*[^:].*$ 中,有两个 .* 因此 : 将与 .* 中的任何一个一起转义。所以,[^:]* 足以捕获所有内容

Regex

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-14
    • 1970-01-01
    • 2017-04-13
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多