【问题标题】:How to replace single quote (') with double quote (") in a file using unix shell script/commands? Apostrophe must not be replaced如何使用 unix shell 脚本/命令将文件中的单引号 (') 替换为双引号 (")?不能替换撇号
【发布时间】:2019-10-29 23:31:11
【问题描述】:

我试图在 Unix 的文件中只用双引号 (") 替换单引号 (') 而不是撇号 (')。撇号 (') 必须保持原样。

我通过按顺序执行 3 个 sed 命令获得了所需的输出。但是,我无法解决最后一行的“假新闻”。

sed -i 's/'\''/"/g' test.txt

sed -i 's/"s/'\''s/g' test.txt

sed -i 's/s"/s'\''/g' test.txt

第一个 sed - 将所有单引号转换为双引号。

2nd sed - 将所有双引号(后跟 s)转换为单引号。

3rd sed - 将所有后跟双引号的 s 转换为单引号。

输入文件-

Hello Sir!
How are you?
How's your health?
All 'good'?
Charles' here.
'fake news'

预期输出-

Hello Sir!
How are you?
How's your health?
All "good"?
Charles' here.
"fake news"

【问题讨论】:

  • 如何处理'fake news'
  • @choroba 是的,我编写的 3 sed 命令将无法处理“假新闻”。我需要解决这个问题。
  • 对于任何解决方案,请考虑它如何处理像'Tis good you're thinkin' 这样的行。 sed 真的无法区分单引号和撇号。
  • 甚至'Tis good the dogs' toys were found - 完全不可能用正则表达式与'The buck stops here' is a quote 之类的东西区分开来。
  • 使用 作为撇号,而不是',因为是正确的排版。

标签: bash shell sed ksh


【解决方案1】:

要重现您的三个sed,您可以使用单个perl 正则表达式:

perl -p -e 's/([^s])'\''([^s])/$1"$2/g' test.txt

编辑:“假新闻”案例

您可以通过以下方式处理一半的“假新闻”案例:

perl -p -e 's/([^s]|^)'\''([^s])/$1"$2/g' test.txt

要管理“新闻”案例,它需要定义可接受单引号的单词列表(姓名和姓氏)。否则,您可以添加以下过程来更改不以大写开头的单词后的引号:

perl -p -e 's/([^\w][a-z]+)s'\''/$1s"/g' test.txt

在“单个”命令中(使用管道):

perl -p -e 's/([^s]|^)'\''([^s])/$1"$2/g' test.txt | perl -p -e 's/([^\w][a-z]+)s'\''/$1s"/g' 

给出:

先生您好!

你好吗?

你的健康状况如何?

所有“好”?

查尔斯在这里。

“假新闻”

“假新闻”

【讨论】:

  • 's/(?<=[^s])'\''(?=[^s])/"/g' 不捕获。
  • 这行得通。但是根据@choroba 对我的问题的评论,如果在输入文件中写入了“假新闻”,那么这个命令将无法实现目标。
【解决方案2】:

您可以在一次 sed 调用中运行所有命令:

sed 's/'\''/"/g;s/"s/'\''s/g;s/s"/s'\''/g'

sed -e 's/'\''/"/g' -e 's/"s/'\''s/g' -e 's/s"/s'\''/g'

【讨论】:

  • 正如您在评论中提到的,3 sed 命令将无法解决“假新闻”。但是,将所有 3 个 sed 命令组合并调用为一个命令确实很有帮助。但需要想办法解决“假新闻”。
【解决方案3】:

这可以通过一个替代命令满足您的要求:

$ sed -E "s/'([^']*)'/\"\1\"/g" file
Hello Sir!
How are you?
How's your health?
All "good"?
Charles' here.
"fake news"

上面的方法是用双引号对替换单引号对。

'([^']*)' 匹配单引号后跟除单引号后跟单引号之外的任何字符。单引号内的字符保存在捕获组 1 中。替换 \"\1\" 获取捕获组并将其放在双引号内。

虽然这可以处理您要求的案例,但很容易想象如果没有复杂的语言分析就无法处理更复杂的案例。

另类风格

可以用另一种(但等效的)shell引用样式编写与上述相同的命令:

sed -E 's/'\''([^'\'']*)'\''/"\1"/g' file

【讨论】:

  • 好吧,那是赢家。我尝试使用\B(不是单词边界),但最终使用Charles"。在我想出一个解决方案之前你就知道了。从sed -r "s/(\B'|'\B)/\"/g" file 开始,并试图从那里开始工作......
  • 我的评论'Tis good you're thinkin' 中的输入失败。它将它变成"Tis good you"re thinkin',而不是保留所有三个撇号。
  • 是的,@chepner,虽然我们可以解决该示例,正如我的回答和您的评论所暗示的那样,但在其他情况下,如果没有完整的语言分析(即此处超出范围)。
猜你喜欢
  • 1970-01-01
  • 2019-07-07
  • 2018-11-18
  • 1970-01-01
  • 1970-01-01
  • 2017-12-29
  • 2012-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多