正则表达式在匹配后删除行

时间:2016-10-30 06:37:49

标签: ruby regex

我试图匹配域example.com,我想删除它下面的所有IP

输入:

[example.com]
10.100.251.1
10.100.251.2
10.100.251.3
[example.net]
10.100.251.22
10.100.251.33

期望的输出:

[example.net]
10.100.251.22
10.100.251.33

这是我到目前为止所尝试的内容:

\[example.com\](\s+^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$)*

它有效,但不确定这是否有效。

我正在使用rubular进行正则表达式测试是一个示例

http://rubular.com/r/cavVHWPvT2

5 个答案:

答案 0 :(得分:1)

我不会为复杂的正则表达式而烦恼,我会使用Ruby slice_before来做这件事:

data = '[example.com]
10.100.251.1
10.100.251.2
10.100.251.3
[example.net]
10.100.251.22
10.100.251.33
'

data.lines.slice_before(/\A\[/).select { |ary| ary.first[/example\.net/] }.join
# => "[example.net]\n10.100.251.22\n10.100.251.33\n"

打破它:

data
  .lines # => ["[example.com]\n", "10.100.251.1\n", "10.100.251.2\n", "10.100.251.3\n", "[example.net]\n", "10.100.251.22\n", "10.100.251.33\n"]
  .slice_before(/\A\[/) # => #<Enumerator: #<Enumerator::Generator:0x007f987b8b4528>:each>
  .select { |ary| ary.first[/example\.net/] } # => [["[example.net]\n", "10.100.251.22\n", "10.100.251.33\n"]]
  .join # => "[example.net]\n10.100.251.22\n10.100.251.33\n"

正则表达式很棒,我会在必要时使用它们,但它们并不总是最适合任务的工具。它们可能非常脆弱且非常危险,并且极大地增加了维护代码的任务,特别是当它们变得更复杂时。

这也可以使用触发器完成,但解释的是留下一个不同的问题:&#34; What is a flip-flop operator?&#34;。

答案 1 :(得分:0)

试试这个:

<强>查找

\[example\.com\].*?(\[(?:(?!example\.com).)*?\])

<强>替换

$1

Regex101

答案 2 :(得分:0)

我们得到了

str =<<-END
[example.com]
10.100.251.1
10.100.251.2
10.100.251.3
[example.net]
10.100.251.22
10.100.251.33
END
  #=> "[example.com]\n10.100.251.1\n10.100.251.2\n10.100.251.3\n[example.net]\n10.100..."

问题有点令人困惑,因为所谓的输出被认为是

[example.net]
10.100.251.22
10.100.251.33

但这也是要删除的内容。接下来的内容返回未删除的行,但更改它以返回已删除的位将是一件简单的事情。此外,问题还不清楚字符串"[example.net]"是否已知,或者它只是"[example.com]"“块”后面的示例。也不清楚是否有两个“块”,如示例中所示,或者可能有一个或两个以上的块。

如果您知道"[example.net]"紧跟"[example.com]"块之后,您可以写

r = /
    \[example\.com\]     # match string
    .*?                  # match any number of characters, lazily
    (?=\[example\.net\]) # match string in positive lookahead
    /mx                  # multiline and free-spacing modes

puts str[r]
[example.com]
10.100.251.1
10.100.251.2
10.100.251.3

如果您不知道"[example.com]"“块”后面的内容,除了下一个块的第一行(如果有的话)包含至少一个字符或句点以外的字符,可以写

r = /
    \[example\.com\]\n  # match string
    .*?                 # match any number of any characters, lazily
    (?:[\d.]*\n)        # match a string containing > 0 digits and periods,
                        # followed by a newline, in a non-capture group
    +                   # match the above non-capture group > 0 times
    /x                  # free-spacing mode

puts str[r]
[example.com]
10.100.251.1
10.100.251.2
10.100.251.3

答案 3 :(得分:0)

你的正则表达非常接近。您错过的是在正确的位置进行分组和换行构造:

/^\[example\.com\]\R*(?:(?:\d{1,3}\.){3}\d{1,3}\R*)*/

请参阅Rubular demo

<强>详情:

  • ^ - 行首
  • \[example\.com\] - [example.com]文字子字符串
  • \R* - 零个或多个换行符(对于较旧的Ruby版本,请使用(?:\r?\n|\r)*
  • (?:(?:\d{1,3}\.){3}\d{1,3}\R*)* - 零个或多个序列
    • (?:\d{1,3}\.){3} - 3个1到3位数的序列和一个点
    • \d{1,3} - 1至3位数字
    • \R* - 0+换行

Ruby demo

str =<<DATA
[example.com]
10.100.251.1
10.100.251.2
10.100.251.3
[example.net]
10.100.251.22
10.100.251.33
DATA
rx = /^\[example\.com\]\R*(?:(?:\d{1,3}\.){3}\d{1,3}\R*)*/
puts str[rx]

答案 4 :(得分:0)

像INI文件一样处理您的数据:扫描部分

处理数据的一种方法是将其视为INI文件。启用了multi-line option的正则表达式可以将INI文件的字符串表示形式分解为多个节的数组,如下所示:

ini = <<~'EOF'
  [example.com]
  10.100.251.1
  10.100.251.2
  10.100.251.3
  [example.net]
  10.100.251.22
  10.100.251.33
EOF

# Scan for INI section headers.
sections = ini.scan /^\[.*?\]$[^\[]*/m

然后,您可以使用Enumerable#grep仅提取所需的部分。例如,要提取example.net部分:

section_title = 'example.net'
sections.grep /\A\[#{Regexp.escape section_title}\]\s*$/
#=> ["[example.net]\n10.100.251.22\n10.100.251.33\n"]

注意事项

  1. 上面的多行正则表达式假设您将整个文件作为单个String对象加载。如果您正在做其他事情,您可能需要采用不同的方法。
  2. 请注意Regexp#escape的重要性,它确保您的字符串被正确转换以用于正则表达式模式。否则,[.]等字符将无法满足您的预期。
  3. INI文件可能比您的示例数据更复杂。您可以考虑编写一个真正的INI解析器,或使用类似inifile的gem,而不是尝试在一个正则表达式中处理所有可能的边缘情况。