如何编辑两个符号之间的文本范围?awk、sed、regex

如何编辑两个符号之间的文本范围?awk、sed、regex

使用“*”符号(不一定是那个,任何特殊字符都可以表示),我如何编辑以下文本:

*berry
straw
rasp
blue
boysen
*
blahblah
blahblah
blahblah
*berry
straw
blue
*
blah
*table
vege
pingpong
*

对此:

strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable

第一个匹配的星号后的每个字符都将放置在每一行上,直到找到第二个星号匹配。

关于我该如何解决这个问题有什么线索吗?(最好使用 sed 或 awk,但如果你能想到其他方法,请告诉我你的代码!)

我知道如何删除所有包含星号的行,只是我想不出字符放置部分

答案1

这段awk代码就足够了:

awk -F'*' 'NF == 2 {label = $2; next} {$0 = $0 label} 1'

具体来说:

  • 用作*字段分隔符。这样,我们可以简单地检查字段的数量(NF)来确定是否已到达块的开头或结尾。
  • 当有两个字段时,我们保存第二个字段label并继续下一行。
  • 然后,我们将其附加label到当前行,然后打印。如果标签为空,则我们在块之外,没有任何效果。如果不是,我们将获得所需的输出。

答案2

在中sed,你可以将“特殊”行复制到保留空间中,然后再删除它

sed -e '/^\*/{h;d;}'

然后将保留空间附加到每个后续的模式空间,替换生成的换行符和标记字符

    -e '{G;s/\n\*//;}'

用你的数据进行测试,

$ sed -e '/^\*/{h;d;}' -e '{G;s/\n\*//;}' file
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable

注意:当遇到第二个星号时,这不会停止;它的作用完全相同,但它会附加*后面没有任何内容 - 直到它匹配下一个*sometext

答案3

这是一个 Perl 方法:

$ perl -lne '/^\*(.*)/ || print "$_$1"' file
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable

解释

-n导致 Perl 读取输入文件的每一行,并将其保存在特殊变量中$_-l将导致它 i)\n从每行中删除尾随换行符 () 和 ii) 在每次调用时添加换行符print-e是应用于每一行的脚本。

  • /^\*(.*)/:匹配以星号开头的行,并将星号后的所有内容保存为$1(这就是括号的作用)。

  • || print "$_$1"'||是逻辑的OR。因此,print只有当前行不是以星号开头时才会执行。如果是这样,我们将打印当前行($_)以及当前保存的内容$1(星号后面的模式)。


像往常一样,有很多方法可以做到这一点。一种愚蠢且低效的方法,但可以突出 shell 的字符串处理能力,它是:

$ while read line; do 
    [[ $line =~ ^\* ]] && pat="${line#\*}" || printf "%s%s\n" "$line" "$pat"; 
  done < file
strawberry
raspberry
blueberry
boysenberry
blahblah
blahblah
blahblah
strawberry
blueberry
blah
vegetable
pingpongtable

解释

  • while read line; do ... ; done < file:这是一个经典的while循环,它将读取输入文件的每一行file并将其保存为$line
  • [[ $line =~ ^\* ]] && pat="${line#\*}":如果行以 开头*,则删除其后的所有内容(这就是 的作用${line#\*},有关更多详细信息,请参阅这里) 并将其保存为$pat。 * || printf "%s%s\n" "$line" "$pat";:如果前一个命令失败(因此,该行不以星号开头),则打印该行和 的当前值$pat

答案4

来晚了。这是另一种python方法:

#!/usr/bin/env python2
with open('/path/to/file.txt') as f:
    for lines in f.read().split('*'):
        entries = lines.rstrip().split('\n')
        for i in range(1, len(entries)):
            print entries[i] + entries[0]

相关内容