LINUX.ORG.RU

Как проверить: является ли строка частью ключа словаря в Python

 


0

1

Добрый день!

Пользователь x3al направил на правильный путь написания скрипта замены английскийских субтитров на русские. Переделанный скрипт примерно такой:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Создаем словать
en2rus = {}
# Открываем файл c переводами
with open("txt") as f:
    # Если открывается
    try:
        # Обрабаываем в цикле
        while True:
            # Первая строка
            FirstLine = next(f)
# Вторая строка
            SecondLine = next(f)
# Заносим первую строку как ключ в словарь, а вторую строку как значение в
# словарь
            # можно заодно любую длину сюда закинуть
            en2rus[FirstLine] = SecondLine
# Обрабатываем ошибку
    except StopIteration:
        pass  # файл кончился

print(en2rus, "- Словарь")

with open("srt") as b, open("srt-out", "w") as out:
    for SrtLine in b:
        print(SrtLine)
        print(dict.keys(en2rus))
        if SrtLine in list(en2rus):
            print(SrtLine, "- SrtLine")

Собственно английское предложение заносится как ключ в словарь, а русский перевод заносится как значание в словарь. И теперь надо проверить совпадает/входит ли пара-тройка английских слов в ключ словаря.

Пробовал dict.keys и list(dict). Не получается. Как лучше реализовать?

Ответ на: комментарий от proud_anon

Опять у меня вложение 4-й степени:

with open("srt") as b, open("srt-out", "w") as out:
    for SrtLine in b:
        for key in en2rus:
            if SrtLine in key:
                print("Есть такая строка в ключе")
chemtech ()
Ответ на: комментарий от proud_anon

Почему- то берет последнее значение:

with open("srt") as b, open("srt-out", "w") as out:
    for SrtLine in b:
        for key in en2rus:
            if SrtLine in key:             
                print(SrtLine)

Берет вот что:

call queuing feature.

Хотя в файле srt вот что:

1
00:00:00,239 --> 00:00:03,280
Like most modern PBXs Asterisk supports a 
call queuing feature.

Как исправить?

chemtech ()
Ответ на: комментарий от proud_anon

Сделал вот так:

with open("srt") as b, open("srt-out", "w") as out:
    for SrtLine in b:
        print(SrtLine,"for SrtLine in b:")
        for key in en2rus:
            print(SrtLine,"for key in en2rus:")          
            if SrtLine in key:
                print(key)                
                print(SrtLine,"if SrtLine in key:")
Like most modern PBXs Asterisk supports a 
 for SrtLine in b:
Like most modern PBXs Asterisk supports a 
 for key in en2rus:
call queuing feature.
 for SrtLine in b:
call queuing feature.
 for key in en2rus:
Like most modern PBXs Asterisk supports a call queuing feature.

call queuing feature.
 if SrtLine in key:

Т.е. «for key in en2rus:» часть фразы видит, но почему дальше не идет.

chemtech ()

Python славится батарейками: для ооочень многих случаев уже есть либо функции в стандартной библиотеке, либо какая-то отдельная.

>>> import pysrt
>>> a = pysrt.open("1.srt")
>>> a[1].start
SubRipTime(0, 4, 27, 929)
>>> a[1].end
SubRipTime(0, 4, 29, 897)
>>> a[1].text
u'Code red.\nCode red.'

Соответствующий кусок srt файла:

2
00:04:27,929 --> 00:04:29,897
Code red.
Code red.

i-rinat ★★★★★ ()
Ответ на: комментарий от chemtech
 print(SrtLine,"for SrtLine in b:")
        for key in en2rus:
            print(SrtLine,"for key in en2rus:")

Во второй раз лучше было печатать key.

Однако всё понятно. У тебя проблема с переносами строк. Он ищет "Like most modern PBXs Asterisk supports a \n" и "call queuing feature.\n". Второе есть, первого — нет.

При чтении файла построчно конец строки не выкидывается автоматически.

proud_anon ★★★★★ ()
Ответ на: комментарий от i-rinat

А как узнать какие методы есть у модуля pysrt? Или как правильно сформулировать вопрос... В гугле искал «как узнать какие методы есть у модуля python»

chemtech ()

И теперь надо проверить совпадает/входит ли пара-тройка английских слов в ключ словаря.

А это зачем?

zolden ★★★★★ ()
Ответ на: комментарий от proud_anon

Похоже получается..

with open("srt") as b, open("srt-out", "w") as out:
    for Line in b:
    	SrtLine=Line.rstrip('\n')
    	# print(SrtLine, "for SrtLine in b:")
    	for key in en2rus:
            # print(SrtLine, "for key in en2rus:")
            if SrtLine in key:
                print(SrtLine)
chemtech ()

кстати первый словарь en2rus наверно проще так заполнять:

with open('txt') as f:
    en2rus = {line.strip():next(f).strip() for line in f}

zolden ★★★★★ ()
Ответ на: комментарий от i-rinat

Python славится батарейками: для ооочень многих случаев

Это уже не первый тред ТСа на эту тему, там не только костыль на костыле, там вся задача в адаптации инвалидного кресла к стоячему положению.

proud_anon ★★★★★ ()
Ответ на: комментарий от chemtech

А как узнать какие методы есть у модуля pysrt?

В документации надо смотреть. Я просто в исходники глянул, увидел определение open. А потом попробовал открыть файл и посмотреть, что он мне выдаст.

i-rinat ★★★★★ ()
Ответ на: комментарий от proud_anon

Постепенно переходим с костылей на инвалидную каляску. Она на колесах :)

chemtech ()
Ответ на: комментарий от chemtech

В коде выше есть StopIteration для моментов когда файл закончится

Ага. И?

zolden ★★★★★ ()
Ответ на: комментарий от proud_anon

Спасибо.!

А еще вопрос. Говорит не может заменить текст:

with open("srt") as b, open("srt-out", "w") as out:
    for Line in b:
    	SrtLine=Line.rstrip('\r\n')
...
                out=b.replace(SrtLine,y[0])
                out.write

Вывод:

    out=b.replace(SrtLine,y[0])
AttributeError: '_io.TextIOWrapper' object has no attribute 'replace'

chemtech ()
Ответ на: комментарий от proud_anon

Можно еще вопрос. Говорит не может заменить текст:

with open("srt") as b, open("srt-out", "w") as out:
    for Line in b:
    	SrtLine=Line.rstrip('\r\n')
...
                out=b.replace(SrtLine,y[0])
                out.write
Вывод:
    out=b.replace(SrtLine,y[0])
AttributeError: '_io.TextIOWrapper' object has no attribute 'replace'

chemtech ()
Ответ на: комментарий от vertinsky

Правильнее проверять принадлежность к типу так:

Да, правильно. Всё время что-нибудь новое про Питон узнаю. Обычно ведь используется утиная типизация без проверки типа, так что, наверное, тип лучше вообще не проверять.

proud_anon ★★★★★ ()
Последнее исправление: proud_anon (всего исправлений: 1)
Ответ на: комментарий от proud_anon

Хотел заменить строку SrtLine - это совпадающая строка из файла srt на строку y[0] - это русский перевод примерно той же длины.

out - это файл, открытый на запись. а b - это файл srt

chemtech ()
Ответ на: комментарий от proud_anon

Вот еще раз код:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import textwrap
import string

with open('txt') as f:
    en2rus = {line.strip():next(f).strip() for line in f}

with open("srt") as b, open("srt-out", "w") as out:
    for Line in b:
    	SrtLine=Line.rstrip('\r\n')
    	for key in en2rus:
            if SrtLine in key:
                Divide_SrtLine_by_LenFirstLine = round(len(SrtLine) / Lenkey, 2)
                print(Divide_SrtLine_by_LenFirstLine, "=", "длина:", SrtLine, "/", "длина:", key)
                ChooseBlockFromSecondLine = round(Divide_SrtLine_by_LenFirstLine * Lenkey)
                print(ChooseBlockFromSecondLine, "= ( длина:", SrtLine, "/ длина:", key, ") * длина:", len(en2rus[key]))
                y=textwrap.wrap(en2rus[key], width=ChooseBlockFromSecondLine)
                print(y[0])
                out=b.replace(SrtLine,y[0],1)
                out.write
chemtech ()
Ответ на: комментарий от proud_anon

Вот эти переменные

SrtLine  - "Like most modern PBXs Asterisk supports a "
------------------------------------------------------------
y[0] - "Как и большинство современных АТС Asterisk"

chemtech ()
Ответ на: комментарий от chemtech

А как узнать какие методы есть у модуля

dir(модуль) ? есть ещё help(), ну и если все сделано праильно, то метод.__doc__ покажет что этот метод делает

Dred ★★★★★ ()
Ответ на: комментарий от proud_anon

Переделал немного скрипт. Но еще есть ошибки. Пример. Вот есть вот такой файл srt:

1
00:00:12,753 --> 00:00:14,762
Agreed.
What's your point?
2
00:00:14,950 --> 00:00:18,140
There's no point, I just think
it's a good idea for a T-shirt.

Вот что получается:

1
00:00:12,753 --> 00:00:14,762
Согласе
смысл?
2
00:00:14,950 --> 00:00:18,140
Нет смысла, я всего лишь
подумал, это хорошая идея для
Сам скрипт
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import textwrap

# Создаем словать
en2rus = {}
# Открываем файл c переводами
with open("txt") as f:
    # Если открывается
    try:
        # Обрабаываем в цикле
        while True:
            # Первая строка
            FirstLine = next(f)
# Вторая строка
            SecondLine = next(f)
# Заносим первую строку как ключ в словарь, а вторую строку как значение в
# словарь
            # можно заодно любую длину сюда закинуть
            en2rus[FirstLine] = SecondLine
            # print(en2rus)
# Обрабатываем ошибку
    except StopIteration:
        pass  # файл кончился

# Открываем файл c переводами
with open("srt") as b, open("srt-out", "w") as out:
    # Если открывается
    try:
        # Обрабаываем в цикле
        while True:
            # Первая строка
            FirstLine = next(b)
            # Номер блока субтитров. Просто записываем
            out.write(FirstLine)
            # Вторая строка. Время субтитра. Просто записываем
            SecondLine = next(b)
            out.write(SecondLine)
            # Третья строка
            ThirdLine = next(b)
            # Убираем знак завершения строки
            SrtLine = ThirdLine.rstrip('\r\n')
            # Перебираем все ключи словаря
            for key in en2rus:
                # Проверяем входит ли строка в ключи словаря - ключи словаря английский текст
                if SrtLine in key:
                    # Определяем длину ключа
                    Lenkey = len(key)
                    # Определяем длину строки
                    LenSrtLine = len(SrtLine)
                    # Определяем длину переведенной строки, от которой нужно отрезать текст
                    y = textwrap.wrap(en2rus[key], width=LenSrtLine)
                    # Заменяем английский текст на перевод
                    ReplaceLine = ThirdLine.replace(SrtLine, y[0])
                    # Записываем замененный текст
                    out.write(ReplaceLine)
            # Четвертая строка
            FourthLine = next(b)
            # Убираем знак завершения строки
            SrtLine = FourthLine.rstrip('\r\n')
            # Если длина строки = 2, тогда просто записываем
            if len(SrtLine) == 2:
                out.write(FourthLine)
            else:
                # Иначе:
                # Перебираем все ключи словаря
                for key in en2rus:
                    # Проверяем входит ли строка в ключи словаря - ключи словаря английский текст
                    if SrtLine in key:
                        # Определяем длину ключа
                        Lenkey = len(key)
                        # Определяем длину строки
                        LenFourthLine = len(SrtLine)
                        # Определяем длину переведенной строки, от которой нужно отрезать текст
                        y = textwrap.wrap(en2rus[key], width=LenSrtLine)
                        # Заменяем английский текст на перевод
                        ReplaceLine = FourthLine.replace(SrtLine, y[1])
                        # Записываем замененный текст
                        out.write(ReplaceLine)
# Обрабатываем ошибку
    except StopIteration:
        pass  # файл кончился

chemtech ()
Ответ на: комментарий от chemtech

Какой страшный код у тебя.

except StopIteration:
        pass  # файл кончился
Вот это самое страшное место.

А что касается твоей проблемы, то, КМК, что ты написал, то ты и получил:

for key in en2rus:
                # Проверяем входит ли строка в ключи словаря - ключи словаря английский текст
                if SrtLine in key:
                    # Определяем длину ключа
                    Lenkey = len(key)
                    # Определяем длину строки
                    LenSrtLine = len(SrtLine)
                    # Определяем длину переведенной строки, от которой нужно отрезать текст
                    y = textwrap.wrap(en2rus[key], width=LenSrtLine)
                    # Заменяем английский текст на перевод
                    ReplaceLine = ThirdLine.replace(SrtLine, y[0])
                    # Записываем замененный текст
                    out.write(ReplaceLine)
Ты отрезаешь от русской строки LenSrtLine символов, где LenSrtLine = длина оригинальной английской строки. Например, строка «Agreed.» превращается в «Согласе».

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

# Определяем длину переведенной строки, от которой нужно отрезать текст
replacement = re.match('^.{{0,{}}}\w*\W?'.format(LenSrtLine), en2rus[key])
# Заменяем английский текст на перевод
ReplaceLine = SrtLine.replace(SrtLine, replacement)

Кроме того, вот тут:

#В последнем else
y = textwrap.wrap(en2rus[key], width=LenSrtLine)
у тебя опечатка, надо было LenFourthLine.

Конечно, правильнее всего было изначально разбивать по словам, а не по символам.

proud_anon ★★★★★ ()
Последнее исправление: proud_anon (всего исправлений: 1)
Ответ на: комментарий от proud_anon

Добрый день. Я знаю, что код страшный. У меня нет ни учителя, ни кого-то другого, где можно спросить. Спросить самое быстрое могу в интернете. Курсов по Python у нас в городе нет. А что такое КМК?

chemtech ()
Ответ на: комментарий от proud_anon

Спасибо за ответ. По поводу «у тебя опечатка, надо было LenFourthLine.»

Я уже пробовал -получаю вот такую ошибку.

    ReplaceLine = FourthLine.replace(SrtLine, y[1])
IndexError: list index out of range

Попробую использовать ваш совет. Спасибо.

chemtech ()

Как проверить: является ли строка частью ключа словаря в Python

needkeys = [x for x in kv.keys() if needstr in x]

то, что ниже - не понял вообще, только испугался

buratino ★★★★★ ()
Ответ на: комментарий от proud_anon

Попробовал заменить

# Определяем длину переведенной строки, от которой нужно отрезать текст
replacement = re.match('^.{{0,{}}}\w*\W?'.format(LenSrtLine), en2rus[key])
# Заменяем английский текст на перевод
ReplaceLine = SrtLine.replace(SrtLine, replacement)

Получаю вот такую ошибку:

    ReplaceLine = SrtLine.replace(SrtLine, replacement)
TypeError: Can't convert '_sre.SRE_Match' object to str implicitly
chemtech ()
Ответ на: комментарий от buratino

ps. чувак, это не python. ты пишешь на каком-то то ли паскале, то ли ещё чём-то, но в python-синтаксисе. ты не пишешь на python-е. писать на python-е *против рожна* очень больно.

полистай pep-8 и pep-20. поставь flake8 и считай даже самый рабочий код неверным, пока есть хоть один warning. не знаю, насколько это поможет, но то, что ты делаешь - это ужасно.

buratino ★★★★★ ()
Ответ на: комментарий от chemtech

У меня нет ни учителя, ни кого-то другого, где можно спросить.

Проблема в том, что вопросы у тебя из серии «Я хочу собрать автомобиль. Я уже взял карбюратор и двигатель, примотал их друг к другу изолентой и приклеил по бокам два деревянных колеса. Как теперь организовать трансмиссию?».

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

Кроме того, ты, пытаясь сэкономить время, выбрал дурацкое решение (разбивать по символам, а не по словам), и теперь убеждаешься в справедливости поговорки «Скупой платит дважды».

А что такое КМК?

«Как мне кажется».

proud_anon ★★★★★ ()

ps. объясни, что тебе нужно в textwrap. и как надо детектить «новые записи» (+1 строка после таймера, или по следующему числу или ещё как?)

остальное - режем текст через .splitlines(), берём текстовые строки (которые не дата и не время), приводим их к единому виду через ' '.join(engstr.split()) - это ключи. так же делаем с переводом, и получаем значение. и тупо заменяем позицию в линии на её значение.

когда это заработает - тогда уже приделывать wrap или что там нужно опционально. а не пытаться решить все задачи в одной функции.

buratino ★★★★★ ()
Ответ на: комментарий от chemtech

меня тоже никто не учил. но я сначала философию понял, потом сделал несколько вещей, и только потом осилил hello, world :)

buratino ★★★★★ ()
Ответ на: комментарий от buratino

Я пытаюсь разделить перевод на части используя textwrap. Т.е. вы хотите из

There's no point, I just think
it's a good idea for a T-shirt.
получить
There's no point, I just think it's a good idea for a T-shirt.
? А потом разбить их?

chemtech ()
Ответ на: комментарий от proud_anon

Что-то не так:

1
00:00:12,753 --> 00:00:14,762
Согласен.А в чем 2
00:00:14,950 --> 00:00:18,140
Нет смысла, я всего лишь подумал,Нет смысла, я всего лишь подумал,

re.match - регулярные выражения?

chemtech ()
Ответ на: комментарий от chemtech

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

блин, задача на python - минут на 5. но я ща ничего не соображаю, от слова «вообще», уже свою пустяшную задачу две недели решаю, что-то тяжелее трёх слов прочесть или продумать сложно, даже текст этот сложно писать :)

решай пока... если за несколько дней не решишь - свистнешь меня, если разум ко мне вернётся и ты мне расскажешь про формат этих файлов субтитров (чё такое 1? какие там бывают даты?), я те сделаю за 5 минут эту фигню.

buratino ★★★★★ ()
Ответ на: комментарий от chemtech

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

то есть, делаешь файл ответов (пишу для второго питона, как там в третьем - не знаю, не интересовался):

afile = open('txt').read().splitlines()
answers = dict(zip(afile[::2],afile[1::2))

(можно и тут, для верности, использовать вместо afile[::2] - [' '.join(x.split) for x in afile[::2]]

и потом проверяешь файл, что-то типа

out = " txtflag = False for n in open('srt').read().splitlines():

в общем, лень всё тут расписывать, но просто отбираешь отдельно вот эти 1,2,3, и пишешь в out, как есть... в общем, я не знаю, какой там формат, но надо разделять, в каких строках текст, в каких - не текст, и из строк с текстом делать буфер, который сравнивать с ключом.

кстати, текст субтитра может быть 3? то есть, 1
дата
Привет, василич
2
дата
Скока время?
3 дата
3 4 дата
вот засада!

если нет - то задача сильно упрощается. на строке, состоящей из цифры - закрывать буфер, и открывать через 2 строки.

buratino ★★★★★ ()
Ответ на: комментарий от buratino

мда, имел я форматирование этого сайта, с его невозможностью написать две строки без code... короче, потом разберёмся, чё и как, но точно не здесь

buratino ★★★★★ ()
Ответ на: комментарий от buratino

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

У него там такая задача:

  • Есть файл srt с английскими субтитрами, с правильными тайм-кодами.
  • Есть txt, в котором английским предложениям сопоставлены русские. При этом каждое предложение в txt может включать в себя несколько частей в srt. Таким образом, правильное разбиение на части с тайм-кодами утрачено.
  • Надо сделать новый файл srt с русскими субтитрами. Для этого предполагается как можно точнее автоматически разбить русские переводы на куски, соответствующие английским, и заменить английские субтитры на русские.

Т.е. разбиение предложений на части — это основная задача.

proud_anon ★★★★★ ()
Ответ на: комментарий от buratino

Пробую заменить ключ и значение в словаре. Новый ключ и новое значение - это срез старого ключа и значения. Отрезаю от ключа найденную строку, от значений - переведенную строку. Но почему то выдает ошибку:

    global en2rus[NewKey] = NewValue
                 ^
SyntaxError: invalid syntax
                # Проверяем входит ли строка в ключи словаря - ключи словаря
                # английский текст
                if SrtLine in key:
                    print(SrtLine,"SrtLine")
                    # Определяем длину ключа
                    Lenkey = len(key)
                    # Определяем длину строки
                    LenSrtLine = len(SrtLine)
                    # Определяем длину переведенной строки, от которой нужно
                    # отрезать текст
                    y = textwrap.wrap(en2rus[key], width=LenSrtLine)
                    # Заменяем английский текст на перевод
                    ReplaceLine = ThirdLine.replace(SrtLine, y[0])
                    print(ReplaceLine, "- ReplaceLine")                    
                    # Узнаем длину замененного текста
                    LenReplaceLine = len(ReplaceLine)                    
                    # Записываем замененный текст
                    # print(key, "key")
                    NewKey = key[LenSrtLine:]
                    print(NewKey, "- NewKey")
                    # print(en2rus[key], "en2rus[key]")
                    NewValue = en2rus[key][LenReplaceLine:]
                    print(NewValue, "- NewValue")
                    global en2rus[NewKey] = NewValue
                    out.write(ReplaceLine)
chemtech ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.