Заменить одиночные кавычки двойным с исключением некоторых элементов
Я хочу заменить все одинарные кавычки в строке на 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
Есть ли какие-либо угловые случаи, которые у меня отсутствуют или есть какие-то лучшие подходы?
Ответы
Ответ 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.