【问题标题】:How do I remove words in a file from a list of words in another .txt file using bash?如何使用 bash 从另一个 .txt 文件中的单词列表中删除文件中的单词?
【发布时间】:2021-04-09 02:13:52
【问题描述】:

我正在尝试使用 sed 删除列表(.txt 文件)中的单词,但它无法正常工作。 输出文件删除了它应该删除的单词以及它不应该删除的部分单词。

这是我尝试过的代码:

sed -E 's/('"$(tr '\n' '|' < listOfWords.txt )"')//gI' file.txt > output.txt

输入示例:

I would love to try or hear the sample audio your app can produce. I do not want to purchase, because I've purchased so many apps that say they do something and do not deliver.  

Can you please add audio samples with text you've converted? I'd love to see the end results.

Thanks!

预期输出:

would love try hear sample audio app can produce. do want purchase, because ve purchased many apps say do something do deliver.  

Can please add audio samples text ve converted? d love see end results.

单词列表示例:

...
I
to
or
the
your
not
so
that
they
and
you
with
Thanks
...

【问题讨论】:

  • 欢迎来到 SO,感谢您在问题中添加您的努力(继续努力)。请在您的问题中添加输入和预期输出示例,以便我们更好地理解它,谢谢。
  • 听起来你想锚定你的正则表达式,所以它只匹配单词边界。这是 GNU sed,还是我们只需要坚持标准强制功能?
  • 还需要一个样本listOfWords.txt 来重现实际输出(并根据所需输出测试建议的答案)。理想情况下,示例应符合minimal reproducible example 规范——这是尽可能短的,在不更改使用时证明问题。如果您只需要删除两个词来显示问题的代码,那么构建一个 2 词列表和围绕它的示例输入/输出有助于保持简洁。

标签: bash shell sed


【解决方案1】:

在您的 sed 表达式中使用 \&lt;\&gt; 可防止删除不在单词边界处开始和结束的项目。请注意,这是一种 GNU 主义——基线 POSIX 标准 sed 可能不支持它。

在下面的复制器中使用 shell 函数而不是文件,因此可以复制和粘贴以进行测试,而无需先创建数据文件:

getListOfWords() {
  printf '%s\n' I to or the your not so that they and you with Thanks
}

getInFile() {
  cat <<EOF
I would love to try or hear the sample audio your app can produce. I do not want to purchase, because I've purchased so many apps that say they do something and do not deliver.  

Can you please add audio samples with text you've converted? I'd love to see the end results.

Thanks!
EOF
}

sed -E 's/\<('"$(tr '\n' '|' < <(getListOfWords) )"')\>//gI' <(getInFile)

...作为输出发射:

 would love  try  hear  sample audio  app can produce.  do  want  purchase, because 've purchased  many apps  say  do something  do  deliver.  

Can  please add audio samples  text 've converted? 'd love  see  end results.

!

...它与您的预期输出相匹配,唯一的例外是该预期输出在删除标点符号方面有一些额外的行为,而原始代码并未尝试实现。

【讨论】:

    【解决方案2】:

    有一种方法可以使用sed -f- 将 sed 命令传送到 sed:

    sed 's|^|s/|; s|$|\\s*//gI|' listOfWords.txt | sed -f- file.txt &gt; output.txt

    这会将 listOfWords.txt 转换为 sed 替换命令并将它们通过管道传递给 sed:

    • 将 listOfWords 中每一行的开头替换为 s/
    • \s*//gI 替换listOfWords 中每一行的结尾
    • 这会导致s/word\s*//gI foreach word 在 listOfWords 中
    • 将替换列表传送到sed -f- file.txt,其中- 表示“标准输入”

    在概念上与 OP 尝试使用 tr 的尝试有些相似,但仅使用由 sed -f- 启用的 sed

    【讨论】:

      【解决方案3】:

      这是一个 Perl 替代方案。第一个参数需要是 listOfWords 文件。

      perl -pe 'BEGIN {open F, shift; $w=join("|", <F>); $w=~s/\n//g;}
                s/\b($w)\b\s*//g;'  /tmp/listOfWords.txt  /tmp/file.txt
      

      正则表达式末尾的\s* 让我们也删除尾随空格以避免多个连续空格。

      您的示例的输出是:

      would love try hear sample audio app can produce. do want purchase, because 've purchased many apps say do something do deliver.  
      
      Can please add audio samples text 've converted? 'd love see end results.
      
      !
      

      如果您还想删除“I”和“you”之后的',可以在单词列表文件的开头添加I'you'

      【讨论】:

        【解决方案4】:

        如果 GNU ed 可用/可接受。

        #!/usr/bin/env bash
        
        ed -s input.txt < <(
          printf '%s\n' ',s/^/\\b/' ',s/$/\\b/' '1,$-1s/$/\\|/' '1;$j' 's/^/,s\//' 's/$/\/\/g/' '$a' ,p w . ,p Q  |
          ed -s listOfWords.txt
        )
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-10-06
          • 1970-01-01
          • 2017-03-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多