提问人:BDR 提问时间:10/26/2016 最后编辑:SundeepBDR 更新时间:10/27/2016 访问量:383
根据外部或内部单引号以不同的方式替换空格
Replace spaces differently depending on outside or inside single quotes
问:
我有输入,其中包含一些字段
- 用空格分隔,
- 其他一些用引号括起来,也用空格分隔
下面是一个示例输入:
active=1 'oldest active'=0s disabled=0 'function call'=0
我想替换:
- 引号外的所有空格均由 和
|
- 所有内部报价
_
输出将为:
active=1|'oldest_active'=0s|disabled=0|'function_call'=0
我尝试了不同的解决方案或在网上找到的解决方案,但没有设法做到我想要的。sed
perl
答:
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
延伸阅读:
- http://perldoc.perl.org/perlre.html
- http://www.rexegg.com/backtracking-control-verbs.html
- http://www.rexegg.com/regex-best-trick.html
评论
0赞
BDR
10/26/2016
哇,多么快速有效的答案!也感谢您的解释。是否有所有可用参数的良好文档(如 SKIP 等)?
0赞
Sundeep
10/26/2016
请参阅 rexegg.com/backtracking-control-verbs.html 和 rexegg.com/regex-best-trick.html
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
评论