根据外部或内部单引号以不同的方式替换空格

Replace spaces differently depending on outside or inside single quotes

提问人:BDR 提问时间:10/26/2016 最后编辑:SundeepBDR 更新时间:10/27/2016 访问量:383

问:

我有输入,其中包含一些字段

  • 用空格分隔,
  • 其他一些用引号括起来,也用空格分隔

下面是一个示例输入:

active=1 'oldest active'=0s disabled=0 'function call'=0

我想替换:

  • 引号外的所有空格均由 和|
  • 所有内部报价_

输出将为:

active=1|'oldest_active'=0s|disabled=0|'function_call'=0

我尝试了不同的解决方案或在网上找到的解决方案,但没有设法做到我想要的。sedperl

Regex Perl AWK SED 行情

评论


答:

2赞 Sundeep 10/26/2016 #1
$ s="active=1 'oldest active'=0s disabled=0 'function call'=0"
$ echo "$s" | perl -pe "s/'[^']*'(*SKIP)(*F)| /|/g; s/ /_/g"
active=1|'oldest_active'=0s|disabled=0|'function_call'=0

两步更换:

  • 首先,将跳过 包围的所有模式,并将剩余的空格替换为'[^']*'(*SKIP)(*F)'|
  • 其次,现在留在里面的空间将被替换为'_


替代解决方案:

$ echo "$s" | perl -pe "s/'[^']*'/$& =~ s| |_|gr/ge; s/ /|/g"
active=1|'oldest_active'=0s|disabled=0|'function_call'=0
  • 这个答案中得到启发
  • '[^']*'/$& =~ s| |_|gr/ge使用另一个 substitute 命令替换匹配模式中的所有空格。修饰符允许在替换部分使用命令而不是字符串'[^']*'e
  • 然后对剩余的空间进行处理s/ /|/g


延伸阅读:

评论

0赞 BDR 10/26/2016
哇,多么快速有效的答案!也感谢您的解释。是否有所有可用参数的良好文档(如 SKIP 等)?
0赞 ssr1012 10/26/2016 #2

我们可以在循环中使用正则表达式。

$str = "active=1 'oldest active'=0s disabled=0 'function call'=0";
print "\nBEF: $str\n";
$str =~s#active=1 'oldest active'=0s disabled=0 'function call'=0# my $tmp=$&; $tmp=~s/\'([^\']*)\'/my $tes=$&; $tes=~s{ }{\_}g; ($tes)/ge; $tmp=~s/ /\|/g; ($tmp); #ge;
print "\nAFT: $str\n";

除此之外,可能会有一些捷径。

1赞 anubhava 10/26/2016 #3

使用 gnu awk ,您可以执行以下操作:FPAT

s="active=1 'oldest active'=0s disabled=0 'function call'=0"

awk -v OFS="|" -v FPAT="'[^']*'[^[:blank:]]*|[^[:blank:]]+" '{
   for (i=1; i<=NF; i++) gsub(/[[:blank:]]/, "_", $i)} 1' <<< "$s"

active=1|'oldest_active'=0s|disabled=0|'function_call'=0
  • 在正则表达式中,我们使用交替来创建所有单引号值+非空格值的字段,即 OR 非空格值,即 从输入。FPAT'[^']*'[^[:blank:]]*[^[:blank:]]+
  • 使用时,我们只需将所有空格替换为 因为我们只会在所有字段的单引号内获得空格。gsub_
  • 最后,我们用OFS='|'|

参考资料:有效的 AWK 编程

评论

1赞 anubhava 10/27/2016
好渔获@Sundeep。现已修复。
1赞 potong 10/27/2016 #4

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

sed -r ":a;s/^([^']*('[^ ']*')*[^']*'[^' ]*) /\1_/;ta;y/ /|/" file

这首先将带引号的字符串中的所有空格替换为 's,然后将剩余的空格转换为 's。_|

1赞 albe 10/27/2016 #5

@anubhava的解决方案让人想起一个老式的Perl解决方案:

$ echo $s | perl -047 -pe "(\$.%2)?s/ /|/g:s/ /_/g;"
active=1|'oldest_active'=0s|disabled=0|'function_call'=0

用单引号 (047) 和基于偶数/奇数的子来划分行。

评论

0赞 Sundeep 10/27/2016
无需使用双引号...perl -047 -pe '($.%2)?s/ /|/g:s/ /_/g;'
0赞 albe 10/29/2016
真。Bash 业余爱好者的标志。
0赞 Ed Morton 10/27/2016 #6
$ awk -F\' '{OFS=FS; for (i=1;i<=NF;i++) gsub(/ /,(i%2?"|":"_"),$i)}1' file
active=1|'oldest_active'=0s|disabled=0|'function_call'=0