regex 当字符串还包含“::“字段分隔符时,匹配单个“:“字段分隔符之间的行中的字符串并排除它们的正则表达式

axzmvihb  于 2022-11-18  发布在  其他
关注(0)|答案(4)|浏览(152)

使用正则表达式,我只需要匹配给定输入字符串中的IPv4子网掩码:

ip=10.0.20.100::10.0.20.1:255.255.254.0:ws01.example.com::off

为了进行测试,此输入字符串包含在一个名为file.txt的文本文件中,但实际的用例将是解析/proc/cmdline,我需要一个解决方案,该解决方案在遇到“ip=”后开始解析、计算字段数和匹配,直到遇到下一白色字符。
我在EL 7.9工作站x86_64上使用bash 4.2.46和GNU grep 2.20来测试表达式。
根据我在其他问题中看到的例子,我提出了下面的grep命令和PCRE正则表达式,它给出的输出非常接近我所需要的。

[user@ws01 ~]$ grep -o -P '(?<!:)(?:\:[0-9])(.*?)(?=:)' file.txt 
:255.255.254.0

我对我在这里所做的事情的理解是,我从一个带有“:“字符的负lookbehind开始,试图排除第一个“::“字段,然后是一个非捕获组,以匹配转义的“:“字符,后面是一个数字[0-9],然后是一个带有.*?的捕获组,用于字符串本身的实际匹配,最后是一个前瞻,以查找下一个“:“字符。
问题是,这会给出所需的字符串,但包含一个额外的:字符串开头的字符。
预期输出应如下所示:

255.255.254.0

让我难以理解的是分隔符不一致。字符串中既包含双冒号,也包含单冒号字段,所以我无法简单地匹配分隔符之间的字符串。原因是字段可以有空值。例如

:<null>:ip:gw:netmask:hostname:<null>:off

此处显示的空值表示用户未传递的省略值,用户不需要为预期目的提供该值。
我已经尝试了几种不同的表达方式,就像在其他答案中建议的那样,使用否定的look behinds和look aheads来避免在a开始匹配:其与另一个相邻:
例如,请参阅以下问题:Regular Expression to find a string included between two characters while EXCLUDING the delimiters
如果我可以从第一个冒号开始匹配,它本身不跟在后面,也不跟在前面:字符,同时排除作为分隔符的冒号字符,并继续匹配,直到下一个也不相邻的冒号:并且不包括冒号字符。
我可以通过在表达式中包含“255”来匹配精确的字符串,如下所示:(适用于我们当前的所有使用情形)

[user@ws01 ~]$ grep -o -P '(?:)255.*?(?=:)' file.txt
255.255.254.0

这里的逻辑问题是子网掩码本身可能不总是以“255”开头,但它应该是一个数字,[0-9],这就是为什么我试图在上面的表达式中使用它。为了简单起见,我不需要验证它不大于255。

tct7dpnv

tct7dpnv1#

使用grep

$ grep -oP '(?<!:)?:\K([0-9.]+)(?=:[[:alpha:]])' file.txt

查看演示here

$ grep -oP '[^:]*:\K[^:[:alpha:]]*' file.txt

输出

255.255.254.0
gkl3eglg

gkl3eglg2#

如果这些是分隔符,则您的值应该位于可明确预测的位置。
只需将 every 冒号作为分隔符,然后选择第4个字段。

$: awk -F: '{print $4}' <<< ip=10.0.20.100::10.0.20.1:255.255.254.0:ws01.example.com::off
255.255.254.0

我不知道你说的是什么意思
让我难以理解的是,分隔符不一致。字符串中既包含双冒号,也包含单冒号字段,所以我无法简单地匹配分隔符之间的字符串。
如果你的分隔符是不可预测和不可解析的,那么它们就毫无用处。如果你的意思是字段可以有引号,也可以没有引号,但是你需要排除引号,我们可以做到这一点。如果双冒号是一种分隔符,而单冒号是另一种分隔符,这是一种糟糕的设计,但我们可能也可以处理这种情况。

$: awk -F'::' '{ split($2,x,":"); print x[2];}' <<< ip=10.0.20.100::10.0.20.1:255.255.254.0:ws01.example.com::off
255.255.254.0

对于报价,您需要提供示例。

w8biq8rn

w8biq8rn3#

使用gnu-grep,您可以将模式写为:

grep -oP '(?<!:):\K\d{1,3}(?:\.\d{1,3}){3}(?=:(?!:))' file.txt

输出量

255.255.254.0

说明

  • (?<!:):负前瞻,向左Assert非:,然后匹配:
  • \K忽略目前匹配的内容
  • \d{1,3}(?:\.\d{1,3}){3}匹配4次1-3个数字,以.分隔
  • (?=:(?!:))正前瞻,Assert后面没有::

请参见regex demo

gfttwv5a

gfttwv5a4#

因为字段的数量总是相同的,只是用“:“分隔,所以你可以使用cut。如果你有空字段,这个解决方案也会起作用。

cut -d":" -f4

相关问题