使用sed命令将第n个单词替换为匹配的模式?

5

我有一个文本文件,具有以下特点:

  1. 每一行至少有三个由空格分隔的“单词”
  2. “单词”可以是任何字符或字符串

我已经在一些行后附加了注释,并提出了对原始单词进行更改的暂定建议,现在希望使用sed来为我进行这些更改。因此,为了更清晰地说明,我的文件如下所示:

NO NO O
SIGNS NN O      #NNS
GIVEN VBD B-VP  #VBN
AT IN O
THIS NN O       
TIME NN O            ## B-NP
. PER O
...

带有1#的注释是用来替换行中的第二个单词,而带有2个#的注释是用来替换行中的第三个单词。 有没有人能够建议一种使用sed(或awk或其他任何东西)实现这个目标的方法?再次澄清(希望如此),我的目标是获取#或##后面的模式,并将该模式替换为行的第n个单词。

谢谢。


能否制定一个规则,使得在#后面的注释有预先确定的空格数量?目前您展示了既有零个又有一个空格的注释,这使得代码不必要地更难适应。如果您的注释在#后面没有空格,那将会更容易些。 - SiegeX
你需要输出中包含注释吗? - SiegeX
@SiegeX:是的,我应该很容易地能够在“## B-NP”中去除多余的空格或者根据需要在“#NNS”中添加空格。 - wayeast
@SiegeX:不,我不想在输出中包含注释——我确实想保留一个标记,比如在几个制表符后面加上“#”来指示我已更改的行。 - wayeast
3个回答

4
这对你有用:

这将对你有用:

awk '/#/{sub(/# +/,"#");n=gsub(/#/,"",$NF);$(n+1)=$NF;$NF="\t\t#"}1' file

解释

  1. /#/{ ... }: 查找包含 # 符号的行,并执行以下步骤...
  2. sub(/# +/,"#"): 如果需要,删除注释和 # 之间的所有空格
  3. n=gsub(/#/,"",$NF): 删除最后一个字段 $NF 中的所有 #,并将删除的 # 数量设置为变量 n
  4. $(n+1)=$NF: 将第 n+1 个字段 $(n+1) 设置为新的最后一个字段 $NF,该字段已删除了所有的 #
  5. $NF="\t\t#": 将最后一个字段 $NF 设置为两个制表符后跟一个 #
  6. 1: 告诉 awk 输出修改后的行的快捷方式
  7. file: 输入文件名

示例

$ awk '/#/{sub(/# +/,"#");n=gsub(/#/,"",$NF);$(n+1)=$NF;$NF="\t\t#"}1' file
NO NO O
SIGNS NNS O             #
GIVEN VBN B-VP          #
AT IN O
THIS NN O
TIME NN B-NP            #
. PER O
...

注意:如果你让笔记始终紧跟着 #,并且中间没有空格,那么你可以删除整个命令中的 sub(/# +/,"#"); 部分,使其更加简短。


谢谢。我对awk不熟悉,所以我需要进行一些学习才能理解这里发生了什么。但我无法将您的注释转换为其他命令。它会是:awk '/#/{;t=$NF;n=gsub(/#/,"",t);$(n+1)=t}1' notes吗?这看起来有点奇怪... - wayeast
它将是/#/{n=gsub(/#/,"",$NF);$(n+1)=$NF;$NF="\t\t#"}1' file - SiegeX
我刚刚在我的文件上运行了你的命令,看起来完美地工作了。我无法感谢你。 - wayeast

1

这个可能适合你:

sed 's/\S*\(\s*\S*\s*#\s*\)\([^#]*\)$/\2\1/;s/ *##*.*/\t\t#/' file
NO NO O
SIGNS NNS O             #
GIVEN VBN B-VP          #
AT IN O
THIS NN O       
TIME NN B-NP            #
. PER O
...

是的,这也起作用。我曾经花费了很长时间在sed中尝试做到这一点,而我想出的命令是噩梦般的。解释器不停地告诉我我的/1和/2标识符无效。 - wayeast
这里的技巧是将正则表达式锚定到字符串的末尾($),并使用额外的#将反向引用拉近一个字段(参见\(\s*\S*\s*#\s*\))。 - potong

0
Perl可以处理这个问题。虽然我认为我更喜欢将其制作成脚本。
粘贴版本:
perl -lnwe 's/#\K\s+//; my @a=/\S+/g; if (@a>3) { $c = $a[3] =~ tr/#//d; $a[$c] = $a[3]; } print join " ", @a[0..2]' file

这个版本将打印到标准输出而不更改文件。添加 -i.bak,例如 perl -i.bak -lnwe '....' 来进行原地编辑,并在 file.bak 中备份。

可读版本:

$ perl -lnwe '       # -l: handle newlines, -n read file/stdin
    s/#\K\s+//;                    # strip optional spaces
    my @a = /\S+/g;                # extract the data
    if (@a > 3) {                  # when there are replacements..
        my $c = $a[3] =~ tr/#//d;  # count and remove #
        $a[$c] = $a[3];            # set element number $c to element 3
    } print join " ", @a[0..2]     # reassemble and print 3 first elements
' file

输出:

NO NO O
SIGNS NNS O
GIVEN VBN B-VP
AT IN O
THIS NN O
TIME NN B-NP
. PER O

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接