sed用2个字符串之间的下划线替换空格

时间:2019-02-09 22:30:51

标签: regex perl awk sed

我有一个包含这样的行的文件

some thing <phrase>a phrase</phrase> some thing else <phrase>other stuff</phrase>

我需要用下划线替换<phrase>标记之间的所有空格。因此,基本上我需要用下划线替换介于></之间的所有空格。我已经在sed,awk和perl中尝试了许多不同的命令,但是还无法使任何东西正常工作。以下是我尝试过的一些命令。

sed 's@>\s+[</]@_@g'

perl -pe 'sub c{$s=shift;$s=~s/ /_/g;$s}s/>.*?[<\/]/c$&/ge'

sed 's@\(\[>^[<\/]]*\)\s+@\1_@g'

awk -v RS='\\[>^[<\]/]*\\]' '{ gsub(/\<(\s+)\>/, "_", RT); printf "%s%s", $0, RT }' infile

我一直在研究这两个问题,试图修改答案以使用所需的字符。
sed substitute whitespace for dash only between specific character patterns

https://unix.stackexchange.com/questions/63335/how-to-remove-all-white-spaces-just-between-brackets-using-unix-tools

有人可以帮忙吗?

6 个答案:

答案 0 :(得分:5)

不要使用正则表达式来解析XML / HTML。

use warnings;
use 5.014;  # for /r modifier
use Mojo::DOM;

my $text = <<'ENDTEXT';
some thing <phrase>a phrase</phrase> some thing else <phrase>other stuff</phrase>
ENDTEXT

my $dom = Mojo::DOM->new($text);
$dom->find('phrase')->each(sub { $_->content( $_->content=~tr/ /_/r ) });
print $dom;

输出:

some thing <phrase>a_phrase</phrase> some thing else <phrase>other_stuff</phrase>

更新: Mojolicious甚至包含一些糖,可以将代码粉碎成一个单行纸:

$ perl -Mojo -pe '($_=x($_))->find("phrase")->each(sub{$_->content($_->content=~tr/ /_/r)})' input.txt

答案 1 :(得分:2)

  

我需要用下划线替换介于></之间的所有空格。

那实际上不会做你想要的,因为在

some thing <phrase>a phrase</phrase> some thing else <phrase>other stuff</phrase>
                  ^^^^^^^^^^^      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

></之间的子字符串覆盖的范围超出了您的想象(上面标记为^)。

我认为用Perl表达需求的最直接方法是

perl -pe 's{>[^<>]*</}{ $& =~ tr/ /_/r }eg'

此处[^<>]用于确保匹配的子字符串不能包含<>(尤其是它不能匹配其他<phrase>标记)。

如果这太可读了,您也可以这样做

perl '-pes;>[^<>]*</;$&=~y> >_>r;eg'

答案 2 :(得分:2)

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

sed -E 's/<phrase>|<\/phrase>/\n&/g;ta;:a;s/^([^\n]*(\n[^\n ]*\n[^\n]*)*\n[^\n]*) /\1_/;ta;s/\n//g' file

通过插入换行符来分隔标签。用下划线迭代替换成对的换行之间的空格。如果没有其他匹配项,请删除引入的换行符。

答案 3 :(得分:1)

另一个Perl,在<phrase>标签之间替换

$ export a="some thing <phrase>a phrase</phrase> some thing else <phrase>other stuff</phrase>"

$ echo $a | perl -lne ' s/(?<=<phrase>)(.+?)(?=<\/phrase>)/$x=$1;$x=~s{ }{_}g;sprintf("%s",$x)/ge ;  print '
some thing <phrase>a_phrase</phrase> some thing else <phrase>other_stuff</phrase>

$

编辑

感谢@haukex,进一步缩短

$ echo $a | perl -lne ' s/(?<=<phrase>)(.+?)(?=<\/phrase>)/$x=$1;$x=~s{ }{_}g;$x/ge ;  print '
some thing <phrase>a_phrase</phrase> some thing else <phrase>other_stuff</phrase>

$

答案 4 :(得分:1)

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

$ awk -v RS='</?phrase>' '!(NR%2){gsub(/\s+/,"_")} {ORS=RT}1' file
some thing <phrase>a_phrase</phrase> some thing else <phrase>other_stuff</phrase>

答案 5 :(得分:1)

如果您是gnu sed在“ d”中的数据;

sed -E ':b s/<(\w+)>([^<]*)\s([^<]*)(<\/\1)/<\1>\2_\3\4/;tb' d