替代偶数或奇数字符串匹配

时间:2019-01-13 22:53:04

标签: linux bash sed terminal pipe

直截了当:这不只是匹配数字。

文档中的许多**散布在 上,我需要用12替换它们。

样本输入

**Lorem ipsum dolor **sit amet, consectetur adipisicing elit. ** 
Ad velit delectus ** quidem itaque eum **accusamus reprehenderit**
illo culpa **** praesentium** ea fugit ****hic in vel officiis, 
expedita sit **** et harum enim quaerat, **** ab corporis quo 
atque perspiciatis. Minima odit obcaecati** ** reiciendis, sed 
rerum ** labore. In fuga, ** aspernatur earum aliquid ** ****** 
**commodi delectus?

所需的输出

1Lorem ipsum dolor 2sit amet, consectetur adipisicing elit. 1 
Ad velit delectus 2 quidem itaque eum 1accusamus reprehenderit2
illo culpa 12 praesentium1 ea fugit 21hic in vel officiis, 
expedita sit 21 et harum enim quaerat, 21 ab corporis quo 
atque perspiciatis. Minima odit obcaecati2 1 reiciendis, sed 
rerum 2 labore. In fuga, 1 aspernatur earum aliquid 2 121 
2commodi delectus?

我唯一想到的是执行一个循环,该循环替换找到的第一个匹配项(s/\*{2}/1/),然后替换第二个匹配项(s/\*{2}/2/),冲洗并重复,但是由于我仍然不这样做不知道如何将其转换为shellscript,我想知道这是否可以通过使用几个管道sed命令来实现。

4 个答案:

答案 0 :(得分:1)

给出:

$ cat file
**Lorem ipsum dolor **sit amet, consectetur adipisicing elit. ** 
Ad velit delectus ** quidem itaque eum **accusamus reprehenderit**
illo culpa **** praesentium** ea fugit ****hic in vel officiis, 
expedita sit **** et harum enim quaerat, **** ab corporis quo 
atque perspiciatis. Minima odit obcaecati** ** reiciendis, sed 
rerum ** labore. In fuga, ** aspernatur earum aliquid ** ****** 
**commodi delectus?

您最好的选择是perlawk

$ perl -lpE 's/\*\*/$cnt++%2+1/ge' file

这使用perl的能力来评估带有替换的表达式。

方法:

  1. 递增计数器$cnt++以获得(0,1,2,3,...)中的每个替换得到的s/\*\*/$cnt++%2+1/ge
  2. 对每个交替替换取该系列的模%2以获得(0,1,0,1,0...),然后添加1以获得(1,2,1,2...)

通过相同的方法,可以将awkwhile循环一起使用:

$ awk '{while (sub(/\*\*/,cnt++%2+1))}1' file

或者,您可以 整个文件(使用-0777),然后对**[stuff between maybe on multiline]**进行全局替换,并替换为1[stuff between maybe on multiline]2

$ perl -0777 -lnE '$s=$_; $s=~s/\*\*([\s\S]*?)\*\*/1${1}2/g; 
                   END{$s=~s/\*\*/1/; say $s;}' file

请注意最后的$s=~s/\*\*/1/;,以防替换总数奇数。

所有三种情况下,打印:

1Lorem ipsum dolor 2sit amet, consectetur adipisicing elit. 1 
Ad velit delectus 2 quidem itaque eum 1accusamus reprehenderit2
illo culpa 12 praesentium1 ea fugit 21hic in vel officiis, 
expedita sit 21 et harum enim quaerat, 21 ab corporis quo 
atque perspiciatis. Minima odit obcaecati2 1 reiciendis, sed 
rerum 2 labore. In fuga, 1 aspernatur earum aliquid 2 121 
2commodi delectus?

答案 1 :(得分:1)

tr '\n' $'\x1' |
sed 's/\*\*/\x2/g' |
sed 's/\x2\([^\x2]*\)\x2/1\12/g; s/\x02/1/' |
tr $'\x1' '\n'
  1. 第一个tr用换行符代替等于十六进制数字0x01的不可读字符。
  2. 然后第一个sed用两个**代替十六进制0x02
  3. 然后将任何模式0x02<anything>0x02替换为1<anything>2
  4. 最后未修改的\x021替换。
  5. 然后将0x01换行。

tutorialspoint的实时版本。

*代替0x02是因为,我们无法沿sed 's/**\(^**\)**/...做一些事情,即。贪婪地匹配一个字符串,直到找到多字符模式(或者我不知道该怎么做)。因此,我只用一个不可更改的字符替换两个字符**并处理它。这样,我可以像*一样正确处理单个**Lor*em ip*sum**

如果您的GNU sed具有-z选项,则不需要替换换行符。

答案 2 :(得分:0)

这可能对您有用(GNU sed):

sed -zE 's/(\*\*)([^*]*(\*[^*]+)*)\1/1\22/g' file

将文件拖入内存。匹配**...**,并在整个文件中全局将**前面的**和1后面的pod 'SwiftDate', '4.5.0' 替换为2。

答案 3 :(得分:0)

使用GNU awk进行多字符RS和RT:

$ awk -v RS='[*][*]' '{ORS=(RT ? (ORS%2+1) : "")}1' file
1Lorem ipsum dolor 2sit amet, consectetur adipisicing elit. 1
Ad velit delectus 2 quidem itaque eum 1accusamus reprehenderit2
illo culpa 12 praesentium1 ea fugit 21hic in vel officiis,
expedita sit 21 et harum enim quaerat, 21 ab corporis quo
atque perspiciatis. Minima odit obcaecati2 1 reiciendis, sed
rerum 2 labore. In fuga, 1 aspernatur earum aliquid 2 121
2commodi delectus?