【问题标题】:Pass the matched value to a function, and replace with the return value将匹配的值传递给函数,并替换为返回值
【发布时间】:2014-10-04 04:06:54
【问题描述】:

如何让 Bash 匹配正则表达式,而不是用常量字符串替换值,而是将匹配的值传递给函数,然后从返回值中获取要替换的值函数。

类似于以下伪代码,它将[a-d] 的每个匹配项替换为相同的字符,但大写:

function uppercase() { echo ${1^^}; }
string="abcdefgh123cbazyz"
echo ${string//[a-d]/uppercase()}
# output: ABCDef123CBAzyz

我并不特别,任何通常安装在 Unix 系统上的语言(例如 sedawk,甚至是 bash 中内置的有限正则表达式支持)都可以使用。

【问题讨论】:

  • 如果我希望匹配是全局的,并不是重复多次运行函数那么简单,因为返回值可能包含反过来被正则表达式匹配的值。跨度>

标签: regex bash awk sed


【解决方案1】:

您可以为此使用 Perl:

perl -lape 's/([a-d])/`uppercase $1`/eg' <<< "$string"

但这需要一个名为uppercase可执行脚本。 Perl e (eval) 标志在匹配时对匹配执行命令。

通过 sed 的另一种方式:

function uppercase() { 
    echo ${1^^} 
}
export -f uppercase
string="abcdefgh123cbazyz"
echo "echo $(sed 's/\([a-d]\)/$(uppercase \1)/g' <<< "$string")" | sh

【讨论】:

    【解决方案2】:

    使用tr:

    echo abcdefgh123cbazyz | tr '[a-d]' '[A-D]'
    

    sed:

    echo abcdefgh123cbazyz | sed -r 's|[a-d]|\U&|g'
    

    输出:

    ABCDefgh123CBAzyz
    

    更新

    Ruby回调:

    puts "abcdefgh123cbazyz".gsub(/[a-d]/){ |m| m.upcase }
    

    使用Python 调用:

    import re
    
    s = "abcdefgh123cbazyz"
    
    def repl(m):
        return m.upper()
    
    print(re.sub('\[\[:(.+?):\]\]', repl, s))
    

    Perl回调:

    my $s = "abcdefgh123cbazyz";
    $s =~ s/([a-d])/uc($1)/eg;
    print "${s}\n";
    

    输出:

    ABCDefgh123CBAzyz
    

    【讨论】:

    • 其中任何一个都可以指向 bash 函数吗? (将字符更改为大写只是一种有限的用例)
    • IQAndreas 使用 Bash 是不可能的。也许它可以与其他可以回调的语言一起使用。
    • @IQAndreas 查看 Python 和 Ruby 回调的更新。
    【解决方案3】:

    Bash 不能在 parameter expansion 中使用用户定义的函数。

    要完成您想要的,请使用 pattern matching 并修改大小写:

    string="abcdefgh123cbazyz"
    echo ${string^^[a-d]}
    

    输出:

    ABCDefgh123CBAzyz
    

    【讨论】:

    【解决方案4】:

    在 Perl 中,您可以使用 e 标志捕获组并将其传递给这样的子例程:

    perl -pe 'sub callback { return uc $_[0] } s/([a-d])/callback $1/eg' <<<"$string"
    

    字符串的输出:

    ABCDefgh123CBAzyz
    

    这里我刚刚为现有函数uc 提供了我自己的包装器,它返回将字母转换为大写。你可以改变子程序的主体来做任何你想做的事情。

    【讨论】:

      【解决方案5】:

      FWIW 以下是您在 GNU awk 中的操作方式(对于 split() 的第 4 个参数):

      $ cat tst.awk                                                
      function uppercase(str) { return toupper(str) }
      {
          split($0,flds,/[a-d]/,seps)
          for (i=1;i in flds; i++) {
              printf "%s%s", flds[i], uppercase(seps[i])
          }
          print ""
      }
      
      $ echo "abcdefgh123cbazyz" | gawk -f tst.awk
      ABCDefgh123CBAzyz
      

      或使用任何 awk:

      $ cat tst.awk                                                
      function uppercase(str) { return toupper(str) }
      {
          while ( match($0,/[a-d]/) ) {
              printf "%s%s", substr($0,1,RSTART-1), uppercase(substr($0,RSTART,RLENGTH))
              $0 = substr($0,RSTART+RLENGTH)
          }
          print
      }
      
      $ echo "abcdefgh123cbazyz" | awk -f tst.awk
      ABCDefgh123CBAzyz
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多