【问题标题】:Replace spaces differently depending on outside or inside single quotes根据外部或内部单引号以不同方式替换空格
【发布时间】:2017-03-09 00:46:36
【问题描述】:

我输入了一些字段

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

这是一个示例输入:

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 quotes


    【解决方案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
    
    • 灵感来自this answer
    • '[^']*'/$& =~ s| |_|gr/ge 使用另一个替换命令替换匹配模式 '[^']*' 中的所有空格。 e 修饰符允许在替换部分使用命令而不是字符串
    • 剩余的空间然后由s/ /|/g处理


    延伸阅读:

    【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案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
      
      • FPAT 正则表达式中,我们使用交替来创建所有单引号值+非空格值(即'[^']*'[^[:blank:]]*)或非空格值(即来自输入的[^[:blank:]]+)的字段。
      • 使用gsub,我们只需将所有空格替换为_,因为我们只会在所有字段中的单引号内获取空格。
      • 最后使用OFS='|',我们用|分隔输出

      参考:Effective AWK Programming

      【讨论】:

      • 好消息@Sundeep。现在已经修复了。
      【解决方案4】:

      @anubhava 的解决方案让人想起老式的 perl 解决方案:

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

      用单引号 (047) 划分行并根据偶数/奇数进行细分。

      【讨论】:

      • 不用双引号...perl -047 -pe '($.%2)?s/ /|/g:s/ /_/g;'
      • 真的。 bash 业余爱好者的标志。
      【解决方案5】:

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

      $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";
      

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

      【讨论】:

        【解决方案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
        

        【讨论】:

          猜你喜欢
          • 2018-11-18
          • 1970-01-01
          • 2019-01-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多