21
2019.01.22snum23 попытался ваш код слегка модифицировать, чтобы обработанные слова не только бы фильтровались re.sub по наличию “:” перед ними, но и еще вертикалью “|” после этих слов.  но ничего не получилось, последнее, что пробовал это такое

Вместо
Код:
for r in dict: s=re.sub('([^\:]{1})' + r[0], r'\1' + r[1], s)

Поставьте
Код:
for r in dict: s=re.sub(r'([^\:]{1})' + r[0] + r'([^\|]{1})', r'\1' + r[1] + r'\2', s)

Функция re.sub работает достаточно просто : re.sub("что искать", "на что заменить", "исходный текст")
1) в "что искать" вы задаете шаблон, в котором круглые скобки "(...)" означают "найти нечто и записать это найденное в переменную". В данном случае выражение "([^\:]{1})" означает "найти символ, отличный от ":", и записать его в первую переменную", а "([^\|]{1})" означает "найти символ, отличный от "|", и записать его во вторую переменную".
2) таким образом, весь шаблон "'([^\:]{1})' + r[0] + '([^\|]{1})'" означает просьбу вида "найти все слова r[0], перед которыми нет ":' и после которых нет "|", причем для каждого найденного совпадения предшествующий символ записать в переменную \1, а последующий в переменную \2".
3) в "на что заменить" указывается текст, на который надо заменить, причем в этом новом тексте возможны ссылки на переменные из "что найдено". В данном случае выражение "r'\1' + r[1] + r'\2'" означает, "заменить каждый найденный блок на r[1], причем слева оставить то, что было в переменной \1, а справа - то, что было в переменной \2".

Одним словом, в данном случае объявление переменных посредством скобок в "что искать" и ссылки на них в "на что заменить" нужно лишь для того, чтобы не потерять символы, соседние с заменяемым словом.
2019.01.23
Ответить
22
2019.01.23Рейхсканцлер Функция re.sub работает достаточно просто : re.sub("что искать", "на что заменить", "исходный текст")

буду по чу-чуть разбираться в питоне и в regex в частности
спасибо большое за помощь! программку уже почти идеальная для моих целей 22
ChinesePlus.ru - кликабельные субтитры, лексика HSK, тексты с озвучкой, книги на китайском и др.
2019.01.23
Ответить
23
2019.01.23Рейхсканцлер Поставьте
Код:
for r in dict: s=re.sub(r'([^\:]{1})' + r[0] + r'([^\|]{1})', r'\1' + r[1] + r'\2', s)
таким образом, весь шаблон "'([^\:]{1})' + r[0] + '([^\|]{1})'" означает просьбу вида "найти все слова r[0], перед которыми нет ":' и после которых нет "|", причем для каждого найденного совпадения предшествующий символ записать в переменную \1, а последующий в переменную \2".

нужна помощь снова, я пока не догоняю.
В самом конце я прогоняю слова из единичных иероглифов. Поэтому вместо вашего кода
Код:
for r in dict: s=re.sub(r'([^\:]{1})' + r[0] + r'([^\|]{1})', r'\1' + r[1] + r'\2', s)
я пробовал ставить такой
Код:
for r in dict: s=re.sub(r'([^\:\w]{1})' + r[0] + r'([^\|]{1})', r'\1' + r[1] + r'\2', s)

с той целью, чтобы иероглиф 界 не влазил бы в обработанный [qtip:世界上|в мире, во всем мире|shìjiè shang]. То есть 世 и 上 благодаря вашему коду игнорируются при выполнении sub, но если слова трех- или четырехсложные, то все еще влазит внутрь кто-нибудь Smile
моя модификация помогает, но при этом остаются не обработанными некоторые stand-alone иероглифы, то есть программу надо прогонять заново, чтобы были доработаны оставшиеся, а это 麻烦 и главное тупо.

плюс бывают случаи, что у меня иероглифы стоят в графе "перевод", то есть по формату [qtip:你好|привет|nihao] там где "привет" у меня иногда бывают и пояснения на китайском.

Другими словами, есть ли какой-то способ написать regex, который бы игнорировал бы все, что уже обработано, то есть внутри квадратных скобок [], и обрабатывал только те иероглифы, что еще не обработаны? или как мне игнорировать те иероглифы которые стоят между : и | ??

пробовал разные варианты, пока ни один не подошел, пока моих знаний явно не хватает.
Подсобите и в этот раз? Smile

спасибо большое!
2019.02.10
Ответить
24
Рейхсканцлер, сейчас более конкретный вопрос.
С регекс справился, вот этот re находит все иероглифы которые еще не обработаны, при этом стоят вне [ ]
Код:
r'(?=\])([\s\S]+?)(?=\[)
обратный соответсвенно вот это. Он выделяет все что внутри [ ] вместе с квадр. скобками.
Код:
(?=\[)([\s\S]+?)(?<=\])

вот здесь видно наглядно как этот regex работает

не получается у меня именно сама замена в re.sub Sad
не понимаю почему не работает этот код, результата просто не появляется, приходится перезагружать терминал
Код:
for r in dict: s=re.sub(r'(?=\])([\s\S]+?)(?=\[)', r[1], s)

по идее ведь выделил ту область где замена должна быть, вставил на что заменять, но не робит. Что не так в моем re.sub?
2019.02.21
Ответить
25
2019.02.21snum23 Рейхсканцлер, сейчас более конкретный вопрос.

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

Вместо строки
Код:
for r in dict: s=re.sub(r'([^\:]{1})' + r[0] + r'([^\|]{1})', r'\1' + r[1] + r'\2', s)

Поставьте строку
Код:
for r in dict: s=re.sub(r'(^|\])([^\[\]]*)(\[|$)',lambda m:m.group(1)+re.sub(r[0],r[1],m.group(2))+m.group(3),s)

Теперь логика такая:
1) первый re.sub ищет в тексте "необработанные" фрагменты, которые лежат вовне скобок [...] , то есть которые начинаются символом "]" и заканчиваются символом "[" (или которые ограничены началом/концом всего текста, если нужных символов не нашлось). За поиск таких фрагментов отвечает регулярное выражение r'(^|\])([^\[\]]*)(\[|$)'. При этом все то, что попало внутрь скобок [...] , будет пропускаться без всяких изменений.
2) для обработки каждого такого фрагмента вызывается некоторая функция, которая объявляется в этой же строке (посредством специального слова "lambda")
3) эта функция в переданном ей тексте посредством второго re.sub делает уже обычную замену иероглифов на [qtip:...]

Короче говоря, внешний re.sub разбивает строку на фрагменты, лежащие вне скобок, а внутренний re.sub делает замену в каждом полученном фрагменте.

Единственное, неясно, как это все будет работать с большими текстами порядка мегабайтов и/или при наличии слишком большого числа заменяемых слов (порядка десятков тысяч). Посмотрите там на ваших объемах. Если будет тормозить, есть еще одно решение, оно точно очень быстрое, но его сложнее писать.

.zip replace.py.zip (Размер: 695 байт / Загрузок: 21)
2019.02.26
Ответить
26
2019.02.26Рейхсканцлер Видимо, при наличии слов, состоящих из 3-х и большего числа иероглифов, надо усложнять логику и делать вложенный re.sub.

Вместо строки
Код:
for r in dict: s=re.sub(r'([^\:]{1})' + r[0] + r'([^\|]{1})', r'\1' + r[1] + r'\2', s)

Поставьте строку
Код:
for r in dict: s=re.sub(r'(^|\])([^\[\]]*)(\[|$)',lambda m:m.group(1)+re.sub(r[0],r[1],m.group(2))+m.group(3),s)

спасибо огромное!!!
при наших объемах этого уже вполне достаточно, так что быстрый вариант даже пока не открывал. Будем работать с этим вариантом пока что

еще раз спасибо, очень мощно помогли с этими программками
2019.02.27
Ответить
27
Рейхсканцлер, у вас высшее образование техническое, а китайский уже после учить начали? Или наоборот?
2019.02.27
Ответить
28
2019.02.26Рейхсканцлер Поставьте строку
Код:
for r in dict: s=re.sub(r'(^|\])([^\[\]]*)(\[|$)',lambda m:m.group(1)+re.sub(r[0],r[1],m.group(2))+m.group(3),s)

Теперь логика такая:
1) первый re.sub ищет в тексте "необработанные" фрагменты, которые лежат вовне скобок [...] , то есть которые начинаются символом "]" и заканчиваются символом "[" (или которые ограничены началом/концом всего текста, если нужных символов не нашлось). За поиск таких фрагментов отвечает регулярное выражение r'(^|\])([^\[\]]*)(\[|$)'.

прошу еще помочь с regex, поскольку вы уже в курсе.
Данный regex отлично работает для китайского текста, но появилась необходимость поработать с обычными языками, где есть собственно пробелы. Данный regex ищет сплошной текст за пределами скобок. Как к нему добавить \b\w*\b, чтобы он выделял именно отдельные слова за пределами скобок?
какие-то простые вещи, да, re.sub понятно как делать, когда такие штуки с группами начинаются, плюс лямбда - когда смотришь как другие делают, вроде бы понятно, когда самому что-то сделать - вообще не понять что к чему. Подскажите, плиз, куда и что здесь вставить, чтобы разбивка на слова шла?

спасибо!
2019.05.12
Ответить
29
snum23

Вы, конечно, правильно смотрите в сторону ключа \b.  Вот рабочий вариант:
Код:
def replace_word(old_word,new_word,s):
   return re.sub(r'(?<=\b)'+old_word+r'(?=\b)', new_word, s, flags=re.IGNORECASE | re.UNICODE)

s=open(sys.argv[2], 'rb').read().decode("UTF-8")
for r in dict: s=re.sub(r'(^|\])([^\[\]]*)(\[|$)',
   lambda m:m.group(1)+replace_word(r[0],r[1],m.group(2))+m.group(3),s)
open(sys.argv[3], 'wb').write(s.encode("UTF-8"))


Только учтите, что
1) ключ \b работает и для границ слов в китайском, поэтому если заменять слово "不" в "不错不", скрипт не сработает (ибо 不错不 = 不错 + 不). Так что на китайском надо без \b.
2) русскоязычные файлы на вход надо подавать по-прежнему в кодировке UTF-8
2019.05.12
Ответить
30
2019.05.12Рейхсканцлер snum23

Только учтите, что
1) ключ \b работает и для границ слов в китайском, поэтому если заменять слово "不" в "不错不", скрипт не сработает (ибо 不错不 = 不错 + 不). Так что на китайском надо без \b.
2) русскоязычные файлы на вход надо подавать по-прежнему в кодировке UTF-8

спасибо огромное! прекрасно работает (правда, убрал ignorecase пока что)
каким образом с уровня новичка (уровень, примерно, то что в тюториалах обычно обучают на ютюбе) доходить вот до такого, что вы пишите? То есть re.sub с группами плюс лямбда плюс еще отдельный функцию под это дело - это крутой уровень как по мне, очень хотелось бы осилить самостоятельно такое

еще раз благодарю!

PS: про \b понятно, что не нужен с иероглифами. Данный скрипт нужен как раз для европейских языков: русский, фр. и инглиш
2019.05.12
Ответить