如何使用正则表达式匹配更大模式的模式?

时间:2014-08-07 05:09:26

标签: regex sed

我在下面有一些代码,并且只想匹配定义_AA(见下面的代码)时定义的版本字符串。

#ifdef _AA
    #define VER 1.0.0.1
    #define VER2 1.0.0.1
#else
    #define VER 1.0.0.1
    #define VER2 1.0.0.1
#endif

我使用这种模式匹配每个版本字符串:

[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+

但我不知道如何只匹配代码 _AA part 中的版本字符串。

c.f。我正在使用gnu sed,最终目标是增加匹配版本字符串的次要版本号。

3 个答案:

答案 0 :(得分:3)

要仅在_AA区域内匹配,请使用地址说明符:

$ sed -n -r '/_AA/,/#else/ {/[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+/p}' file
    #define VER 1.0.0.1
    #define VER2 1.0.0.1

工作原理:

  • -n

    这告诉sed不要打印任何行,除非我们明确要求它。

  • -r

    这会选择扩展的正则表达式格式。

  • /_AA/,/#else/

    这是地址范围选择器。当遇到_AA的行时,它会开始匹配。它继续并包括匹配#else的第一行。

  • /[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+/p

    在与范围选择器匹配的行中,选择并打印与版本正则表达式匹配的行。

    [.]是匹配句点的好方法。虽然.通常是通配符,但在方括号中它会失去特殊含义。

增加次要版本号

您提到最终目标是增加次要版本号。我会选择awk来执行此任务,因为sed不擅长数学:

$ awk -F. -v OFS=. '/_AA/,/#else/ {if (/[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+/) {$NF=$NF+1}}; {print}' file
#ifdef _AA
    #define VER 1.0.0.2
    #define VER2 1.0.0.2
#else
    #define VER 1.0.0.1
    #define VER2 1.0.0.1
#endif

工作原理:

  • -F. -v OFS=.

    这告诉awk为输入和输出字段分隔符使用句点。使用.作为字段分隔符,可以轻松地增加次要版本号。

  • /_AA/,/#else/ {if (/[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+/) {$NF=$NF+1}};

    这从/_AA/,/#else/开始,这是一个地址范围选择器,就像sed版本一样。

    在该地址范围内的行中,if语句进一步选择具有版本号的行。对于这些行,最后一个字段$NF是次要版本号,并且加1。

  • {print}

    最后,所有行都会打印出来。

正确编辑文件

使用sed,可以使用-i选项(或OSX上的-i"")对文件进行编辑。

新版本的GNU awk(4.1.0或更高版本)也有一个就地编辑选项,类似于“sed -i”。

对于awk的旧版本,可以按如下方式模拟就地编辑:

awk  -F. -v OFS=. '/_AA/,/#else/ {if (/[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+/) {$NF=$NF+1}}; {print}' file > tmp && mv tmp file

sed -i而较新的awk并未真正进行就地编辑。它们还会写入临时文件,然后使用它来覆盖源文件。因此,就地功能仅仅是打字快捷方式。

答案 1 :(得分:1)

如果您愿意接受其他建议;使用Perl单行程序在这些模式之间打印版本字符串。

perl -ne 'if (/_AA/../#else/) { print unless /_AA/ or /#else/ }' file
    #define VER 1.0.0.1
    #define VER2 1.0.0.1

如果您想删除前导空格:

perl -ne 'if (/_AA/../#else/) { s/^\s+// and print unless /_AA/ or /#else/ }' file
#define VER 1.0.0.1
#define VER2 1.0.0.1

答案 2 :(得分:0)

您可以使用此正则表达式:

(\d+\.){3}\d+

<强> Working demo