在一个非常大的文件上替换字符串

String replace on a very large file

我有一个巨大的文本文件 JSON。你可以在这里看到它:http://api.mtgdb.info/cards/。我已将此 JSON 保存到名为 cards.json.

的文件中

cards.json 中,我需要用反斜杠 \ 转义每个单引号 '

所以我需要用\'替换'

通常这在任何编辑器中都是微不足道的,但是文件太大了。 如何转义此字符串中的所有单引号?

我试过的:

  1. 我尝试使用 sed。我的命令是 sed s/\'/\\'/ cards.json > cards_cleaned.json。然而 cards_cleaned.json 文件没有任何转义 ',它只是 cards.json 的精确副本。 Sed 在我执行 sed s/\'/foobar/ cards.json > cards_cleaned.json 时工作,所以我假设我的转义反斜杠有问题。

  2. 我尝试使用 vim。我在 vim $ vi cards.json 中打开了 cards.json。然后我尝试使用 :%s/'/\'/g 进行全局字符串替换。这并没有改变文件中的任何内容。

在 Vi 中,您需要转义 \ 字符。

尝试使用

:%s/'/\'/g

对我来说很有效。

Test.txt

\'\'\' \'\'\'

sed "s/'/\\&/g" cards.json > cards_cleaned.json
  • 无需在搜索模式中进行第一次转义 \'
  • 你应该用双引号括起来(如果单引号不是要更改的字符,则为单引号)并转义由于在这种情况下 shell 级别使用的双引号

你需要双重逃避backelas,所以使用:

sed -i.bak "s/'/\\'/g" cards.json

您需要在 shell 中使用双引号以避免引用单引号字符,但是您必须小心,因为 shell,对于双引号字符串,使用反斜杠作为引用字符

$ echo "eoieriou'iouou'oiuiouiuo"|sed "s/'/\'/g"
eoieriou'iouou'oiuiouiuo

并且 sed 试图执行的命令是 s/'/\'/gsed 引号字符是反斜杠,因此您可以用单引号替换每个单引号...

我们必须在到达sed时引用反斜杠,所以让我们尝试

$ echo "eoieriou'iouou'oiuiouiuo"|sed "s/'/\\'/g"  # Four (4) backslashes in a row
eoieriou\'iouou\'oiuiouiuo
$ 

没关系,不是吗?因为 sed 被指示执行 s/'/\'/g 以便从 sed 的 POV 中引用的字符是反斜杠本身...

请注意,单引号或双引号不是 sed POV 中的特殊字符,它们仅在 shell.

的上下文中是特殊的

你可以这样使用,在vim。

 :%s/'/\\'/g

在 sed 中,

 sed "s/'/\\'/g" filename

这是一个 awk 版本:

cat file
hi'more data here'

awk '{gsub(g,"\"g)}1' g="'" file
hi\'more data here\'

或者如果您需要双反斜杠:

awk '{gsub(g,"\\"g)}1' g="'" file
hi\'more data here\'

虽然@anubhava 或@gboffi 的答案有效,但它们会产生 INVALID JSON.

JSON allows only backslash:

后的几个字符
\"
\
\/
\b
\f
\n
\r
\t
\u four-hex-digits

例如以下部分原文(正确)JSON

[
   {
      "description" : "Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land's controller.",
      "rarity" : "Rare",
      "name" : "Ankh of Mishra"
   }
]

你想得到

[
   {
      "description" : "Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land\'s controller.",
      "rarity" : "Rare",
      "name" : "Ankh of Mishra"
   }
]
#e.g. instead of the land's want land\'s

但这是无效的 JSON。

所以,如果你(出于某种奇怪的原因)想要 backslash,你需要使用双 \,例如:

[
   {
      "description" : "Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land\'s controller.",
      "rarity" : "Rare",
      "name" : "Ankh of Mishra"
   }
]

解决方案(两者都适用)

perl

perl -pE "s/'/\\'/g" < mtg_cards.json > cards.malformed.json
#changes "land's" to wrong "land\'s"

perl -pE "s/'/\\'/g" < mtg_cards.json > card_with_double_BS.json
#changes "land's" to "land\s"

Ps:因为你的文件只有一行(30MB),所以vim有一些问题。在编辑之前,您可以 pretty print(折叠和缩进)JSON。这里有很多工具,我使用的是 JSON_XS perl 包中的 json_xs 命令。在 "prettyfying" 之后你可以安全地使用 vim