【问题标题】:How to find and extract all words appearing between brackets?如何查找和提取出现在括号之间的所有单词?
【发布时间】:2015-09-16 09:16:17
【问题描述】:

如何将文本文件中括号之间出现的所有单词放入数组中,并将其替换为该数组中的随机单词?

cat math.txt
First: {736|172|201|109} {+|-|*|%|/} {21|62|9|1|0}
Second: John had {22|12|15} apples and lost {2|4|3}

我需要这样的输出:

First: 172-9
Second: John had 15 apples and lost 4

【问题讨论】:

  • 在我看来,在 Bash 中这样做会很痛苦。 Perl 或 Python 呢?这里stackoverflow.com/questions/2388488/… 可能是您的起点。
  • 您想要一种可以使用自定义 repl 函数进行正则表达式替换的语言。 Bash 或 sed 不是其中之一。我不声称自己是 awk 专家,但据我所知,这在 awk 中也很难。这在 Python 中是轻而易举的事。

标签: arrays bash awk sed grep


【解决方案1】:

这在 awk 中是微不足道的:

$ cat tst.awk
BEGIN{ srand() }
{
    for (i=1; i<=NF; i++) {
        if ( match($i,/{[^}]+}/) ) {
            n = split(substr($i,RSTART+1,RLENGTH-2),arr,/\|/)
            idx = int(rand() * (n-1)) + 1
            $i  = arr[idx]
        }
        printf "%s%s", $i, (i<NF?OFS:ORS)
   }
}

$ awk -f tst.awk file
First: 172 - 9
Second: John had 22 apples and lost 2
$ awk -f tst.awk file
First: 201 - 9
Second: John had 12 apples and lost 2
$ awk -f tst.awk file
First: 201 + 62
Second: John had 12 apples and lost 2
$ awk -f tst.awk file
First: 201 + 1
Second: John had 12 apples and lost 4

只需检查设置idx 的行上的数学 - 我认为它是正确的,但没有考虑太多。

【讨论】:

    【解决方案2】:
    $ awk 'BEGIN{srand()} {for (i=1;i<=NF;i++) {if (substr($i,1,1)=="{") {split(substr($i,2,length($i)-2),a,"|"); j=1+int(rand()*length(a)); $i=a[j]}}; print}' math.txt
    First: 172 + 1
    Second: John had 12 apples and lost 3
    

    工作原理

    • BEGIN{srand()}

      这会初始化随机数生成器。

    • for (i=1;i&lt;=NF;i++) {if (substr($i,1,1)=="{") {split(substr($i,2,length($i)-2),a,"|"); j=1+int(rand()*length(a)); $i=a[j]}

      这会遍历每个字段。如果任何字段以{ 开头,则substr 用于删除字段的第一个和最后一个字符,其余部分以| 作为分隔符拆分为数组a。然后,选择数组a 中的随机索引j。最后,将字段替换为a[j]

    • print

      如上修改的那行被打印出来了。

    与上面相同的代码,但重新格式化为多行,是:

    awk 'BEGIN{srand()}
    {
        for (i=1;i<=NF;i++) {
            if (substr($i,1,1)=="{") {
                split(substr($i,2,length($i)-2),a,"|")
                j=1+int(rand()*length(a))
                $i=a[j]
            }
        }
        print
    }' math.txt
    

    修正了空格问题

    假设match.txt 现在看起来像:

    $ cat math.txt 
    First: {736|172|201|109} {+|-|*|%|/} {21|62|9|1|0}
    Second: John had {22|12|15} apples and lost {2|4|3}
    Third: John had {22 22|12 12|15 15} apples and lost {2 2|4 4|3 3}
    

    最后一行在{...} 中有空格。这改变了 awk 划分字段的方式。对于这种情况,我们可以使用:

    $ awk -F'[{}]' 'BEGIN{srand()} {for (i=2;i<=NF;i+=2) {n=split($i,a,"|"); j=1+int(n*rand()); $i=a[j]}; print}' math.txt
    First:  736   +   62 
    Second: John had  12  apples and lost  3 
    Third: John had  15 15  apples and lost  2 2
    

    它是如何工作的:

    • -F'[{}]'

      这告诉 awk 使用 }{ 作为字段分隔符。

    • BEGIN{srand()}

      这会初始化随机数生成器

    • {for (i=2;i&lt;=NF;i+=2) {n=split($i,a,"|"); j=1+int(n*rand()); $i=a[j]}

      使用我们对字段分隔符的新定义,偶数字段是大括号内的字段。因此,我们在| 上拆分这些字段并随机选择一个并将字段分配给该字段:$i=a[j]

    • print

      如上修改该行,我们现在打印它。

    【讨论】:

    • 如果我想将其中一条线更改为如下所示:第二:John 有 {22 22|12 12|15 15} 个苹果并丢失了 {2 2|4 4|3 3} 如何解决这个问题,因为您的解决方案不起作用
    • @MarcinWojcik 这改变了很多事情。我刚刚添加了一个新的解决方案来处理这些空间。
    【解决方案3】:

    你可以试试这个 awk:

    awk -F'[{}]' 'function rand2(n) { 
       srand();
       return 1 + int(rand() * n);
    }
    {
       for (i=1; i<=NF; i++)
          if (i%2)
             printf $i OFS;
          else {
             split($i, arr, "|");
             printf arr[rand2(length(arr))]
          };
          printf ORS
    }' math.txt
    
    First:  736  -  62
    Second: John had  22 apples and lost  2
    

    以上的更多运行可能会产生:

    First:  172  *  9
    Second: John had  12 apples and lost  4
    
    First:  109  /  0
    Second: John had  15 apples and lost  3
    
    First:  201  %  1
    Second: John had  12 apples and lost  3
    
    ...
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-05
      • 1970-01-01
      • 1970-01-01
      • 2020-12-19
      相关资源
      最近更新 更多