Заменить вложенные двойные кавычки - PullRequest
1 голос
/ 01 июля 2019

Я хотел бы заменить вложенные двойные кавычки на двойной апостроф в документе 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 ]

3 голосов
/ 01 июля 2019

Данные, введенные вами, представляют собой HTML и встроенный JSON, причем JSON разбивается вдребезги.

Я бы максимально использовал парсеры, чтобы приблизиться к этому.Для HTML мы можем использовать lxml, что позволяет легко получить доступ к текстовому содержанию интересующего элемента (<script type="application/ld+json">) с помощью XPath.

Когда у нас есть элемент text, мы можем использовать 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, неоднократно пытаясь проанализироватьпока он не преуспеет или не столкнется с ошибкой, которую он еще не знает, как исправить.

# 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 голос
/ 01 июля 2019

Вы можете использовать следующее регулярное выражение:

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

См. Демоверсию regex

Детали

  • (:\s+") - Группа 1: :, 1+ пробелов, "
  • (.*(?:\n(?!\s*"[^"\n:]+":).*)*) - Группа 2:
    • .* - любые 0+ символов, кроме символов разрыва строки, как можно больше
    • (?:\n(?!\s*"[^"\n:]+":).*)* - 0 или более повторений
      • \n(?!\s*"[^"\n:]+":) - символ новой строки, за которым не следует 0+ пробелов, ", 1+ символов, отличных от новой строки, " и :, а затем ": подстрока
      • .* - любые 0+ символов, кроме символов разрыва строки, как можно больше

См. Демоверсию Python :

s = re.sub(r'(:\s+")(.*(?:\n(?!\s*"[^"\n:]+":).*)*)",$', lambda x: '{}{}",'.format(x.group(1), x.group(2).replace('"', "''")), s, flags=re.M)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...