正则表达式模式匹配两行 - 搜索和替换

时间:2016-01-30 21:52:47

标签: regex

我有一份需要帮助的文本文档。在下面的示例中是制表符分隔文本doc的摘录,其中3行模式的第一行始终是数字。 Doc将始终采用此格式,并在三行中的每一行上使用相同的选项卡式。

nnnn **variable** V -------
* FROM CLIP NAME - **variable**
* LOC: variable variable **variable**

我想用第三行的第四个字段替换第一行的第二个字段。然后将第二行冒号后面的字段替换为第一行上的原始第二个字段。正则表达式可以实现吗?我习惯单线搜索替换功能但不习惯多线模式。

000003  A009C001_151210_R6XO             V     C        11:21:12:17 11:21:57:14 01:00:18:22 01:01:03:19 
*FROM CLIP NAME:  5-1A 
*LOC: 01:00:42:15 WHITE   005_NST_010_E02 
000004  B008C001_151210_R55E             V     C        11:21:18:09 11:21:53:07 01:01:03:19 01:01:38:17 
*FROM CLIP NAME:  5-1B 
*LOC: 01:01:20:14 WHITE   005_NST_010_E03 

结果如下:

000003  005_NST_010_E02             V     C        11:21:12:17 11:21:57:14 01:00:18:22 01:01:03:19 
*FROM CLIP NAME:  A009C001_151210_R6XO
*LOC: 01:00:42:15 WHITE   005_NST_010_E02 
000004  005_NST_010_E03             V     C        11:21:18:09 11:21:53:07 01:01:03:19 01:01:38:17 
*FROM CLIP NAME:  B008C001_151210_R55E 
*LOC: 01:01:20:14 WHITE   005_NST_010_E03 

非常感谢提前。

1 个答案:

答案 0 :(得分:1)

正则表达式定义regular language。单独,这只表达了一些输入的结构。对此输入执行操作需要某种处理工具。你没有指定你使用的工具,所以我选择。

多行sed

您写道,您“习惯于单线搜索替换功能,但不习惯多线模式”。也许你指的是sed的替换。见How can I use sed to replace a multi-line string?。它比单行更复杂,但它是可能的。

AWK脚本

AWK以其强大的单行程而闻名,但您也可以编写脚本。这是一个脚本,它使用正则表达式来标识新记录/模式的开头以匹配第一个数字。 (我毫不犹豫地将其称为“记录”,因为它在AWK中具有特定含义。)它存储前两行的字段,直到遇到第三行。在第三行,它具有进行所需替换所需的所有信息。然后它打印修改后的前两行并继续。第三行打印不变(您指定第三行没有替换)。如果在下一个记录/模式开始之前还有其他行,它们也将保持不变。

由于提交系统已将其替换为空格,因此不清楚样本输入中制表符的确切位置。我假设FROM CLIP NAME:和下面的字段之间有一个标签,第一行和第三行的“变量”也是以制表符分隔的。如果每个记录/模式的第一个数字是十六进制而不是十进制,请将[[:digit:]]替换为[[:xdigit:]]

<强> fixit.awk

#!/usr/bin/awk -f

BEGIN { FS="\t"; n=0 }
{n++}
/^[[:digit:]]+\t/ { n=1 }

# Split and save first two lines
n==1 { line1_NF = split($0, line1, FS); next }
n==2 { line2_NF = split($0, line2, FS); next }
n==3 {
    # At the third line, make replacements
    line1_2 = line1[2]
    line1[2] = $4
    line2[2] = line1_2

    # Print modified first two lines
    printf "%s", line1[1]
    for ( i=2; i<=line1_NF; ++i )
        printf "\t%s", line1[i]
    print ""
    printf "%s", line2[1]
    for ( i=2; i<=line2_NF; ++i )
        printf "\t%s", line2[i]
    print ""
}
1  # Print lines after the second unchanged

您可以像

一样使用它
$ awk -f fixit.awk infile.txt

或在

中管道
$ cat infile.txt | awk -f fixit.awk

这不是最常规的表达式启发式解决方案,但它应该进行您想要的替换。对于更复杂的输入结构,理想的解决方案是编写正确解释完整输入语言的扫描程序和解析器。使用字符串替换等工具可能适用于简单的特定情况,但可能存在一些细微差别和假设,一般不适用。解析器也可以更强大并实现可以表达无法用正则表达式识别的语言的语法。