在单独留下已引用的字符串时引用不带引号的字符串的最佳方法是什么?

时间:2016-08-30 15:20:36

标签: python json regex string sed

我有一大块文本几乎是JSON,但并不完全。我需要使它成为JSON,以便我可以处理它。具体来说,它是"标记"以下页面代码中的对象:https://en.wikipedia.org/wiki/Module:Syrian_Civil_War_detailed_map

已经引用了一些字符串。其中一些不是。我需要引用所有字符串并将已经引用的字符串单独留下。例如,使用以下几乎JSON对象:

marks = {
    lat = 36.103,
    long = 37.308,
    mark = m.gov_hill,
    marksize = 184,
    label = "[[Battle of Aleppo (2012–present)|Aleppo]]",
    link = "Battle of Aleppo (2012–present)",
    label_size = 0,
    position = "left"
}

我需要它成为这个:

"marks" = {
    "lat" = 36.103,
    "long" = 37.308,
    "mark" = "m.gov_hill",
    "marksize" = 184,
    "label" = "[[Battle of Aleppo (2012–present)|Aleppo]]",
    "link" = "Battle of Aleppo (2012–present)",
    "label_size" = 0,
    "position" = "left"
}

基本上,任何可以成为字符串且不是字符串的东西都应该变成一个字符串。此外,我已经有一个sed命令,用于将等号转换为冒号作为将其转换为有效JSON的步骤之一,因此无需对该过程的这一部分发表评论。

提前致谢!

4 个答案:

答案 0 :(得分:1)

使用正则表达式

(^[^\n\S]*|=\s*)(?![\d\s])(\w+[^,\s]*)

并取代

\1"\2"
你会得到these results。如果您认为将使用不同的正则表达式语言/引擎,则可以从Python切换到任何其他类型。

答案 1 :(得分:0)

这会查找任何尚未包含任何"个字符的行。对于那些在等号后面有字母字符或下划线的行,则等号后面的数字放在引号中:

$ sed -E '/"/!s/= +(.*[[:alpha:]_].*),/= "\1",/' file
marks = {
    lat = 36.103,
    long = 37.308,
    mark = "m.gov_hill",
    marksize = 184,
    label = "[[Battle of Aleppo (2012–present)|Aleppo]]",
    link = "Battle of Aleppo (2012–present)",
    label_size = 0,
    position = "left"
}

更详细:

  • -E

    这告诉sed使用扩展正则表达式。

  • /"/!

    这告诉sed从考虑中删除任何已经有双引号的行。

  • s/= +(.*[[:alpha:]_].*),/= "\1",/

    如果数量有字母字符或下划线字符,则此替换命令将等号后面的数字放在双引号中。

更改文件

要更改文件,请使用-i选项:

sed -i.bak -E '/"/!s/= +(.*[[:alpha:]_].*),/= "\1",/' file

答案 2 :(得分:0)

分别处理每行文本(假设项目不跨越行)

删除尾随逗号

在第一个等号

处拆分每一行

对于通过拆分生成的每个子项目:

  • 剥离前导/尾随空格
  • 如果它等于{},请不要管它。
  • 如果int()float()成功,请不要理会。
  • 如果它以引号开头,请不要管它(假设没有不平衡的报价)
  • 否则请添加引号

重新组合已处理的行,并根据需要添加逗号

答案 3 :(得分:0)

$ cat tst.awk
/=/ {
    lhs = rhs = $0
    sub(/[[:space:]]*=.*/,"",lhs)
    sub(/^[^=]+=[[:space:]]*/,"",rhs)

    sub(/[^[:space:]]+/,"\"&\"",lhs)

    if ( rhs !~ /^([0-9]+\.?[0-9]*|".*"),?$/ ) {
        sub(/,?$/,"\"&",rhs)
        rhs = "\"" rhs
    }

    $0 = lhs " = " rhs
}
{ print }

$ awk -f tst.awk file
"marks" = "{"
    "lat" = 36.103,
    "long" = 37.308,
    "mark" = "m.gov_hill",
    "marksize" = 184,
    "label" = "[[Battle of Aleppo (2012–present)|Aleppo]]",
    "link" = "Battle of Aleppo (2012–present)",
    "label_size" = 0,
    "position" = "left"
}

以上内容应该适用于我在你的问题评论中提到的非平凡案例。