替换嵌套的双引号

时间:2019-07-01 09:11:40

标签: regex python-3.x

我想用json文档中的双撇号替换嵌套的双引号。

我尝试了以下代码,但是我的正则表达式模式未选择需要更改的正确组。

# fixing double quote
try:
    result = re.search('claimReviewed": "(.*)",',page,re.UNICODE | re.IGNORECASE)
    if result is not None:
        double_quoted = result.group(1)
        print(double_quoted)
        double_quoted_fixed = double_quoted.replace('"', '\'\'')
        page = page.replace(double_quoted, double_quoted_fixed)
except AttributeError as e:
    print(e)
return page

我的测试字符串是:

    "sameAs": "https://www.facebook.com/sonnoktasayfasi/photos/a.673944945978789/2319632444743356/?type=3&theater"
    },
    "datePublished": "02/05/2019"
  },
  "claimReviewed": "İDDİA: Diyanet İşleri Başkanlığı ''Çocuklara Zekâ Geliştirici Oyuncaklar Vermeyin" şeklinde bir açıklama yaptı. "

我的代码段返回以下内容,仅更改为第一双引号:

    "sameAs": "https://www.facebook.com/sonnoktasayfasi/photos/a.673944945978789/2319632444743356/?type=3&theater"
    },
    "datePublished": "02/05/2019"
  },
  "claimReviewed": "İDDİA: Diyanet İşleri Başkanlığı ''Çocuklara Zekâ Geliştirici Oyuncaklar Vermeyin" şeklinde bir açıklama yaptı. "

,所需的行为是: 第一个正则表达式模式应分组

İDDİA: Diyanet İşleri Başkanlığı "Çocuklara Zekâ Geliştirici Oyuncaklar Vermeyin" şeklinde bir açıklama yaptı.  

,然后将其替换为双撇号,所需的输出应如下:

"claimReviewed": "İDDİA: Diyanet İşleri Başkanlığı ''Çocuklara Zekâ Geliştirici Oyuncaklar Vermeyin'' şeklinde bir açıklama yaptı. ",

2 个答案:

答案 0 :(得分:3)

您输入的数据是HTML和嵌入式JSON,而JSON则被破坏了。

我将尽可能使用解析器来解决这个问题。对于HTML,我们可以使用lxml,使用XPath可以轻松获取有趣元素(<script type="application/ld+json">)的文本内容。

有了元素文本后,可以使用json.loads()。此方法适用于示例页面上的第一个此类元素,但不适用于第二个元素,出现"Expecting ',' delimiter"错误。

有问题的部分是:

"claimReviewed": "İDDİA: Diyanet İşleri Başkanlığı "Çocuklara Zekâ Geliştirici Oyuncaklar Vermeyin" şeklinde bir açıklama yaptı.

&nbsp;",

正确的是:

"claimReviewed": "İDDİA: Diyanet İşleri Başkanlığı \"Çocuklara Zekâ Geliştirici Oyuncaklar Vermeyin\" şeklinde bir açıklama yaptı.\n\n&nbsp;",

所以有两件事要解决:

  • 在双引号前缺少反斜杠
  • 文字换行符必须替换为\n

之后,JSON应该进行解析。

我们可以使用JSON解析器中的异常信息在JSON中进行适当的修复,反复尝试对其进行解析,直到解析成功或遇到某种尚不知道如何解决的错误为止。 / p>

# json_utils.py
import json

class JsonRepairError(Exception):
    def __init__(self, e, text):
        message = "Don't know how to fix '%s', position %s (-->%s<--)" % (e.msg, e.pos, text[e.pos-5:e.pos+5])
        super().__init__(message)
        self.text = text

def json_repair(text):
    while True:
        try:
            return json.loads(text)
        except json.decoder.JSONDecodeError as e:
            if e.msg == "Expecting ',' delimiter":
                if text[e.pos-1] == '"':
                    text = text[:e.pos-1] + '\\' + text[e.pos-1:]
                    continue
                elif text[e.pos-2] == '"':
                    text = text[:e.pos-2] + '\\' + text[e.pos-2:]
                    continue
            elif e.msg == "Invalid control character at":
                if text[e.pos] == '\n':
                    text = text[:e.pos] + '\\n' + text[e.pos+1:]
                    continue

            raise JsonRepairError(e, text) from None

我们可以这样使用:

import requests
from html import unescape
from lxml import html
from json_utils import json_repair

response = requests.get("https://gist.githubusercontent.com/isspek/6b687e69bbfbb1f5519de5c13e92e4da/raw")
tree = html.fromstring(response.content)

elem = tree.findall('.//script[@type="application/ld+json"]')[-1]
text = unescape(elem.text)  # this gets rid of the stray &nbsp; in the data

data = json_repair(text)
print(data["claimReviewed"])

这将打印正确的输出:

İDDİA: Diyanet İşleri Başkanlığı "Çocuklara Zekâ Geliştirici Oyuncaklar Vermeyin" 
şeklinde bir açıklama yaptı.

 

优点是可以轻松地将这种方法适应以前未处理的任何类型的错误-只需添加几对if / elif检查并进行适当的修复即可。使用正则表达式很难做到这一点。它对HTML格式的更改也更具弹性,并且总体上更易于维护。

答案 1 :(得分:1)

您可以使用以下正则表达式:

(:\s+")(.*(?:\n(?!\s*"[^"\n:]+":).*)*)

请参见regex demo

详细信息

  • (:\s+")-第1组::,1个以上的空格,"
  • (.*(?:\n(?!\s*"[^"\n:]+":).*)*)-第2组:
    • .*-除换行符以外的任意0+个字符,并且尽可能多
    • (?:\n(?!\s*"[^"\n:]+":).*)*-重复0次或更多次
      • \n(?!\s*"[^"\n:]+":)-换行符,其后不跟0+空格,",除换行符之外的1+个字符,":,然后是{{1} }子字符串
      • ":-除换行符以外的任意0+个字符,并且尽可能多

请参见Python demo

.*