Подтвердить что ты не робот

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

Я хочу заменить все одинарные кавычки в строке на double, за исключением таких случаев, как "not", "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

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

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

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,

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

Изменить 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

Есть ли какие-либо угловые случаи, которые у меня отсутствуют или есть какие-то лучшие подходы?

4b9b3361

Ответ 1

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

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

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

DEMO IN REGEX101

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

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

Случай s '

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

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

DEMO IN REGEX101

ВЫПОЛНЕНИЕ ПИТОНА

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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"\"\2\""

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.

Демо

Ответ 4

Вот не-regex способ сделать это

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"

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

Ответ 5

Вот еще один возможный способ:

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.