正则表达式:为啥这些行中的文字“鲍勃”不匹配?

Posted

技术标签:

【中文标题】正则表达式:为啥这些行中的文字“鲍勃”不匹配?【英文标题】:Regex: Why isn't the literal 'bob' matched in these lines?正则表达式:为什么这些行中的文字“鲍勃”不匹配? 【发布时间】:2022-01-23 06:56:14 【问题描述】:

即使bob 不在行中,我如何更新此正则表达式以使其匹配? (Python)。

^(AllowUsers.*) (\bbob\b) ?(.*)$

我幼稚的想法是在捕获组 2 上添加一个“0 或 1”量词:(\bbob\b)?,但是当我这样做时,除了结尾之外的某处有 bob 的行不再匹配:

### without "?" on capture group 2
# Match
AllowUsers bob
AllowUsers bob billybob
AllowUsers billybob bob
AllowUsers billybob steve bob eric bobby
AllowUsers billybob bobby steve bob eric
AllowUsers richard bob
AllowUsers richard bob jeremy
AllowUsers bob james richard jeremy
AllowUsers bob jeremy

# no match
AllowUsers james richard jeremy

### With "?" on capture group 2:
# All lines match, but `bob` is not captured unless it's at the end of the line:
AllowUsers bob               # `bob` captured
AllowUsers billybob bob      # `bob` captured
AllowUsers bob billybob      # `bob` not captured

我对正则表达式(第 2 组使用 ?)的理解是:

^(AllowUsers.*) :匹配以AllowUsers 开头的行并捕获之后的任何内容(第 1 组),不包括空格。这太贪心了。 (\bbob\b)?:匹配并捕获bob(第 2 组)(如果存在)。我们使用单词边界 (\b) 来避免错误匹配,例如 billybob ?(.*)$:匹配一个可选空间,然后捕获任何内容(第 3 组)。

这是 regex101 链接:https://regex101.com/r/39zNfm/1

如果我删除 (\bbob\b) 上的“0 或 1”量词,那么我匹配所有包含 bob 的行,并且我得到正确的捕获组,我不再匹配没有bob 的行。

我误会了什么?

所需的匹配和捕获行为

正则表达式应匹配以AllowUsers 开头的任何行,无论该行中是否存在bob。 如果bob 不在行中,则捕获整行。分两组进行:第 1 组和第 3 组。第 3 组为空也可以。 如果bob 在行中,则捕获(第 1 组)之前的所有内容,包括(第 2 组)和之后(第 3 组)

例如:

背景

我正在使用 lineinfile 内置函数编写 Ansible 任务。此任务的目标是将用户添加到/etc/ssh/sshd_configAllowUsers 指令。

对于lineinfile,使用的正则表达式必须匹配修改前后的行,这样才能保持幂等性。

最后,任务如下所示:

- name: "Allow  user  to log in via SSH"
  lineinfile:
    path: '/etc/ssh/sshd_config'
    state: present
    regexp: "^(AllowUsers.*) (\b user \b)?(\w*)$"  # not currently workng
    line: "\1  user  \3"   # might have to fiddle with literal space. eg: "\1 user\3"
    backrefs: yes
  loop:  ssh_users 
  loop_control:
    loop_var: user

【问题讨论】:

把它改成(\bbob\b)? 真的没什么。就您的意图而言,很难说出这个压缩的正则表达式 ^(AllowUsers.*) (\bbob\b) ?(.*)$ 意味着什么。 "将其更改为 (\bbob\b)?" 我不确定您的意思。在 OP 中,我提到我正是这样做的,但是如果在字符串中间找到它,它就不再捕获 'bob'。 “很难说出这个压缩的正则表达式......就你的意图而言意味着什么”。我认为我在“期望的行为”部分中很清楚。您能详细说明不清楚的地方吗? 【参考方案1】:

如果我正确理解了您的问题,这就是诀窍:^(AllowUsers.*)?(\bbob\b)|(.*) 请参阅regex demo 并检查右侧的说明 - 键是 ?|("alternate")

编辑: 由于您更新的测试用例不匹配任何不以“AllowUsers”开头的内容并且需要将该匹配作为第 1 组,这里有一个解决方案:^(AllowUsers )(?>(.*)?(\bbob\b)(.*)|(.*))$regex demo

编辑 #2: 发布上述编辑后,注意到对三组捕获的 OP 请求的更改。于是模式进一步细化如下:^(?|(AllowUsers.+?(?=\bbob\b))(\bbob\b)(.*)|(AllowUsers .*))$regex demo of Edit #2

这使用分支重置模式,(?|alternation)。有关这方面的更多信息,请参阅Use branch reset grouping to number captures in alternations 另外,请参阅match everything up to (but not including) the exact sequence "abc" 以了解.+?(?=abc) 模式的说明

【讨论】:

该死的!这几乎正​​是我所需要的。唯一的问题是捕获组 1 需要在其中包含字符串的开头(“AllowUsers ...”),以便反向引用替换正常工作。正如您的回答一样,将所有内容都放在组 3 中(对于没有“bob”的行)。我会到处玩,看看我能得到什么。 哦,您的正则表达式也将匹配 以 AllowUsers 开头的行 :-( 我应该将其包含在我的原始测试用例中 是的。稍后我会处理它,但如果你之前修复它,请在此处发布。 @dthor 最后的编辑可能是您正在寻找的。您可能需要修剪捕获组中的额外空间。希望这可以帮助。干杯! 请注意:python 的 stdlib re 模块确实支持分支重置模式。您必须使用 regex 模块 (github.com/mrabarnett/mrab-regex)。我将把它标记为答案 - 现在我只需要破解 Ansible 来使用 regex...

以上是关于正则表达式:为啥这些行中的文字“鲍勃”不匹配?的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式不匹配,不知道为啥[重复]

只能输入文字,数字,大小写英文的js正则表达式.

为啥这个正则表达式不匹配这个文本?

正则表达式.+可以匹配空格,但是[.\w]+却不匹配,为啥?

为啥这个正则表达式不生成匹配?

为啥这个正则表达式模式不匹配? [复制]