Заменить одинарные кавычки на двойные, с исключением некоторых элементов

Я хочу заменить все одинарные кавычки в строке на double за исключением вхождений, таких как" n't"," 'll"," 'm" и т. д.

input="the stackoverflow don't said, 'hey what'"
output="the stackoverflow don't said, "hey what""

код 1:(@https://stackoverflow.com/users/918959/antti-haapala)

def convert_regex(text): 
     return re.sub(r"(?<!w)'(?!w)|(?<!w)'(?=w)|(?<=w)'(?!w)", '"', text)

есть 3 случая: "не предшествует и не следует буквенно-цифровой символ; или не предшествует, но следует буквенно-цифровой символ; или предшествует и не следует буквенно-цифровой символ характер.

проблема: это не работает со словами, которые заканчиваются Апострофом, т. е. большинство притяжательных множественных, и это также не работает на неформальном аббревиатуры, начинающиеся с Апострофа.

код 2:(@https://stackoverflow.com/users/953482/kevin)

def convert_text_func(s):
    c = "_" #placeholder character. Must NOT appear in the string.
    assert c not in s
    protected = {word: word.replace("'", c) for word in ["don't", "it'll", "I'm"]}
    for k,v in protected.iteritems():
        s = s.replace(k,v)
    s = s.replace("'", '"')
    for k,v in protected.iteritems():
        s = s.replace(v,k)
    return s

слишком большой набор слов, чтобы указать, как можно указать лиц и т. д. Пожалуйста помочь.

Edit 1: Я использую замечательный ответ @анубхавой по. Я столкнувшись с этой проблемой. Иногда, есть языковые переводы, которые подход терпят неудачу. Код=

text=re.sub(r"(?<!s)'(?!(?:t|ll|e?m|s|d|ve|re|clock)b)", '"', text)
:

в тексте "Kumbh melas" melas-это перевод с хинди на английский, а не множественное число притяжательных существительных.

Input="Similar to the 'Kumbh melas', celebrated by the banks of the holy rivers of India,"
Output=Similar to the "Kumbh melas', celebrated by the banks of the holy rivers of India,
Expected Output=Similar to the "Kumbh melas", celebrated by the banks of the holy rivers of India,

Я ищу, может быть, добавить условие, которое каким-то образом исправляет его. Вмешательство на уровне человека-последний вариант.

Edit 2: Наивный и долгий подход к исправлению:

def replace_translations(text):
    d = enchant.Dict("en_US")
    words=tokenize_words(text)
    punctuations=[x for x in string.punctuation]
    for i,word in enumerate(words):
        print i,word
        if(i!=len(words) and word not in punctuations and d.check(word)==False and words[i+1]=="'"):
            text=text.replace(words[i]+words[i+1],words[i]+""")
    return text

есть ли угловые случаи I отсутствует или есть какие-то лучшие подходы?

5 ответов


первая попытка

вы также можете использовать это регулярное выражение:

(?:(?<!\w)'((?:.|\n)+?'?)'(?!\w))

ДЕМО В REGEX101

это регулярное выражение соответствует всему предложению / слову с обеих цитирующих меток, от начала и до конца, но также campure содержание цитаты внутри группы nr 1, поэтому вы можете заменить сопоставленную часть на "".

  • (?<!\w) - отрицательный lookbehind для символа без слова, чтобы исключить такие слова, как: "вы будете" и т. д., но разрешить регулярное выражение чтобы соответствовать quatations после символов, таких как \n,:,;,. или -, etc. Предположение, что перед цитатой всегда будет пробел, является рискованным.
  • ' - одиночная метка цитаты,
  • (?:.|\n)+?'?) - non захватывая группа: один или больше из любого характера или новая строка (для сопоставления многострочных предложений) с ленивым quantifire (чтобы избежать соответствие от первого до последнего одиночного знака цитирования), а затем опционный одиночный цитировать поет, если было бы 2 внутри ряд
  • '(?!\w) - одинарные кавычки, за которыми следует символ без слова, чтобы исключить текст типа "Я"," ты " и т. д. где цитирование Марка является beetwen слова,

дело s

однако у него все еще есть проблема с сопоставлением предложений с апострофами происходит после окончания слова на s, например:'the classes' hours'. Я думаю, что невозможно отличить с regex, когда s следовал по ' следует рассматривать как конец цитаты, или как или s С апострофы. Но я вычислил своего рода ограниченную работу для этой проблемы с regex:

(?:(?<!\w)'((?:.|\n)+?'?)(?:(?<!s)'(?!\w)|(?<=s)'(?!([^']|\w'\w)+'(?!\w))))

ДЕМО В REGEX101

РЕАЛИЗАЦИЯ PYTHON

С дополнительной альтернативой для случаев с s': (?<!s)'(?!\w)|(?<=s)'(?!([^']|\w'\w)+'(?!\w) где:

  • (?<!s)'(?!\w) - если нет s до ', соответствуют как регулярное выражение выше (первая попытка),
  • (?<=s)'(?!([^']|\w'\w)+'(?!\w) - если есть s до ', конец матча на этом ' только если нет другого ' затем не слова символ в следующем тексте, перед концом или перед другим ' (но только ' предшествует письмо, кроме s, или открытия следующего quotaion). The \w'\w включить в такой матч a ', которые находятся между буквами, как в i'm, etc.

это регулярное выражение должно совпадать неправильно только оно есть пара s' дела подряд. Тем не менее, он далек от совершенства решение.

недостатки \w

также, используя \w всегда есть шанс, что ' произойдет после sybol или non-[a-zA-Z_0-9] но все же буквенный символ, как какой-то местный языковой символ, и тогда он будет рассматриваться как начало четверостишия. Этого можно избежать, заменив (?<!\w) и (?!\w) С (?<!\p{L}) и (?!\p{L}) или что-то вроде (?<=^|[,.?!)\s]), etc., положительный lookaround для символов, которые могут возникнуть в предложении перед quatation. Однако список может быть довольно долго.


Вы можете использовать:

input="I'm one of the persons' stackoverflow don't th'em said, 'hey what' I'll handle it."
print re.sub(r"(?<!s)'(?!(?:t|ll|e?m)\b)", '"', input)

выход:

I'm one of the persons' stackoverflow don't th'em said, "hey what" I'll handle it.

RegEx Demo


попробуйте это: вы можете использовать это регулярное выражение ((?<=\s)'([^']+)'(?=\s)) и заменить на ""

import re
p = re.compile(ur'((?<=\s)\'([^\']+)\'(?=\s))')
test_str = u"I'm one of the persons' stackoverflow don't th'em said, 'hey what' I'll handle it."
subst = u"\"\""

result = re.sub(p, subst, test_str)

выход

I'm one of the persons' stackoverflow don't th'em said, "hey what" I'll handle it.

демо


здесь это не описаный способ сделать это

text="the stackoverflow don't said, 'hey what'"

out = []
for i, j in enumerate(text):
    if j == '\'':
        if text[i-1:i+2] == "n't" or text[i:i+3] == "'ll" or text[i:i+3] == "'m":
            out.append(j)
        else:
            out.append('"')
    else:
        out.append(j)

print ''.join(out)

дает в качестве выхода

the stackoverflow don't said, "hey what"

конечно, вы можете улучшить список исключений, чтобы не использовать вручную проверять каждое исключение...


вот еще один возможный способ сделать это:

import re

text = "I'm one of the persons' stackoverflow don't th'em said, 'hey what' I'll handle it."

print re.sub("((?<!s)'(?!\w+)|(\s+'))", '"', text)

Я попытался избежать необходимости в особых случаях, это дает:

I'm one of the persons' stackoverflow don't th'em said,"hey what" I'll handle it.