LINUX.ORG.RU

Python. Вопрос по textwrap.wrap и по остальному скрипту тоже.

 


0

1

Добрый день! Пытаюсь написать скрипт для замены английского текста на русский перевод в субтитрах. Сначала был набросок, но потом с помощью волшебных пенделей и гугля, скрипт стал обретать черты. Итак. Есть файл субтитров 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.
И файл перевода:
Agreed.
Согласен.
What's your point?
А в чем смысл?
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
Нет смысла, я всего лишь
подумал, это хорошая идея для
Видно что скрипт обрезает концы строк. Думаю надо как-то подшаманить с textwrap.wrap. Ну и сам скрипт.
#!/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  # файл кончился
Я понимаю что тут много быдлокода, но я еще учусь. Как лучше написать скрипт для замены английского текста на русский перевод в субтитрах?

Я тебе ответил уже:
Как проверить: является ли строка частью ключа словаря в Python (комментарий)

Я понимаю что тут много быдлокода, но я еще учусь.

Метод «херак-херак и в продакшен» — это, ИМХО, прямая противоположность изучению языка. Особенно на начальных стадиях.

proud_anon ★★★★★ ()

Комментарии в коде не на английском - признак дурного тона.

dvrts ★★★ ()

Хватит плодить темы, заебал.

Deleted ()

# Определяем длину ключа
Lenkey = len(key)

ты нигде не используешь этот параметр

Virtuos86 ★★★★★ ()
#!/usr/bin/python3

import pysrt
import textwrap

def read_items(fname, encoding='utf-8'):
    a = []
    for b in open(fname, encoding=encoding):
        a.append(b.rstrip('\r\n'))
        if len(a) == 2:
            yield a
            a = []

def translate(fname, lang, encoding='utf-8', width=20):
    srt = pysrt.open(fname, encoding=encoding)
    for i in srt:
        t = i.text
        t = t.replace('\n', ' ')
        for a, b in lang.items():
            t = t.replace(a, b)
        i.text = textwrap.fill(t, width=width)
    return srt

en2rus = dict(read_items('txt', encoding='utf-8'))
t = translate('srt', en2rus, encoding='utf-8')
t.save('srt-out', encoding='utf-8')
anonymous ()

замены английского текста на русский перевод в субтитрах

Нахера? Учи как есть. Переводи слово и выписывай в словарик бумажный. Ты пишешь какой-то свой гугл транслейт, нафига? Переводи текст на ходу. Есть же какие-то апишки для гугл транслейта. Считываешь строку - шлёшь переводчику, результат сохраняешь во второй файл. А делать ключи словаря в питоне размеров в английское слово, по нему извлекать русское - это всё будет работать до поры до времени, потом наступит аппокалипсис.

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

Прочитал ваш ответ. Запустил. Но почему то не переводит. Вот вывод.

1
00:00:00,004 --> 00:00:03,293
Welcome to asterisk
essentials brought
to you by Digium

2
00:00:03,689 --> 00:00:07,060
The Asterisk
company. We're glad
that you're here and
we're excited to
start

3
00:00:07,006 --> 00:00:08,075
teaching you all
about Asterisk,
chemtech ()
Ответ на: комментарий от chemtech

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

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

Конечно. Извините.

Файл txt

Welcome to asterisk essentials brought to you by Digium The Asterisk company.
Добро пожаловать на уроки Основы Asterisk от Digium, компании создавшей Asterisk.
We're glad that you're here and we're excited to start teaching you all about Asterisk, the world's premier open source telephony platform.
Мы рады, что Вы решили выбрать этот курс и нам не терпится обучить Вас основам Asterisk, ведущей платформы телефонии с открытым исходным кодом.
Before we get to the training videos, that make up this course, we want to take just a few moments to talk about the format of the course.
Прежде чем мы приступим к обучающим видео, из которых состоит этот курс, мы бы хотели поговорить о формате курса.

Файл srt

1
00:00:00,004 --> 00:00:03,293
Welcome to asterisk essentials brought 
to you by Digium

2
00:00:03,689 --> 00:00:07,060
The Asterisk company. We're glad that 
you're here and we're excited to start
Скрипт
#!/usr/bin/python3

import pysrt
import textwrap


def read_items(fname, encoding='utf-8'):
    a = []
    for b in open(fname, encoding=encoding):
        a.append(b.rstrip('\r\n'))
        if len(a) == 2:
            yield a
            a = []


def translate(fname, lang, encoding='utf-8', width=20):
    srt = pysrt.open(fname, encoding=encoding)
    for i in srt:
        print(i, "i translate")
        t = i.text
        print(t, "t translate")
        t = t.replace('\n', ' ')
        print(t, "t translate")
        for a, b in lang.items():
            t = t.replace(a, b)
            print(t, "t translate")
        i.text = textwrap.fill(t, width=width)
        print(i, "i translate")
    return srt

en2rus = dict(read_items('txt', encoding='utf-8'))
t = translate('srt', en2rus, encoding='utf-8')
t.save('srt-out', encoding='utf-8')

Вывод ST3:

1
00:00:00,004 --> 00:00:03,293
Welcome to asterisk essentials brought
to you by Digium
 i translate
Welcome to asterisk essentials brought
to you by Digium t translate
Welcome to asterisk essentials brought to you by Digium t translate
Welcome to asterisk essentials brought to you by Digium t translate
1
00:00:00,004 --> 00:00:03,293
Welcome to asterisk
essentials brought
to you by Digium
 i translate
2
00:00:03,689 --> 00:00:07,060
The Asterisk company. We're glad that
you're here and we're excited to start
 i translate
The Asterisk company. We're glad that
you're here and we're excited to start t translate
The Asterisk company. We're glad that you're here and we're excited to start t translate
The Asterisk company. We're glad that you're here and we're excited to start t translate
2
00:00:03,689 --> 00:00:07,060
The Asterisk
company. We're glad
that you're here and
we're excited to
start
 i translate
[Finished in 0.2s]

Файл srt-out

1
00:00:00,004 --> 00:00:03,293
Welcome to asterisk
essentials brought
to you by Digium

2
00:00:03,689 --> 00:00:07,060
The Asterisk
company. We're glad
that you're here and
we're excited to
start

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

Первый блок:

Welcome to asterisk essentials brought to you by Digium
Словарь с наиболее подходящей фразой:
Welcome to asterisk essentials brought to you by Digium The Asterisk company.
подчеркнут недостающий фрагмент.

Откуда скрипт узнает, что дальше будут именно они? И почему он должен в первый блок вставить полный текст перевода:

Добро пожаловать на уроки Основы Asterisk от Digium, компании создавшей Asterisk.
а не его часть?

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

Первая строка это

Welcome to asterisk essentials brought

Он берет ее длину и заменяет переведенной строкой примерно той же длины.

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

Нельзя так делать без знания последующих элементов субтитров. Давай так, я предложу тебе два пути. Можешь использовать любой из них или отказаться от обоих.

1) описание идеи на словах и дальнейшая твоя реализация. Идея на словах:

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

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

Недостаток приведенного кода: все предложения в сутбитрах должны иметь перевод.

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

Спасибо что помогаете.

У меня сейчас код вот такой примерно: http://pastebin.com/Y62t80eY

разбиваешь все субтитры на пары: слово и элемент субтитров.

А элемент субтитра это что такое?

В вашем коде вопросики. Они там случайно или специально?

Может мне мой код на github выложить?

chemtech ()
Ответ на: комментарий от chemtech
  • А элемент субтитра это что такое?

    Имелось ввиду то, что pysrt разбирает субтитры на список элементов: items -> list of SubRipItem. Default to [].
  • Они там случайно или специально?

    Специально, код генератора шума сразу после строки:

    $ cat noise.py

    шум там используется как мера обучения, о чем я и писал:

    отлаживаешь искаженный мной код

  • Может мне мой код на github выложить?

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

# Если длина строки 'a' равно 2, то

длина списка равна двум. это имеется ввиду то, что прочитана английская и русская строчки.

# Пока дзен yield еще не понял

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

# Иначе значение items увелчивается на 1 - тут я не донца понял.

количество слов в элементе субтитров.

# Вот эта строка непонятная

нужно догадаться до того что было задумано

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

Как дальше понять/расшифровать код?

создать свой чистый проект и потихоньку переносить код из искаженного в свой, отлаживая каждую очередную строку

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

Может поможет это: Размеры файлов исходного и искаженного равны между собой. Каждый знак вопроса скрывает только один печатный символ.

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

Т.е. получается yield это примерно как return - возращает результат.

Теперь понятна строчка. en2rus = dict(read_items('txt', encoding='utf-8')) Там используется функция read_items. Дальше создается словарь из списка.

А как на счет переменных. Ведь их имена могут быть любые?

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

Я имею ввиду, что имена переменных зашифрованы ? и понять как переменная называется сложно. Я понимаю что надо читать код. Но пока я еще не специалист.

Например,

def ????????(???):

Как функция может называться...

Я понимаю что нужно смотреть что она делает. Но пока в я вижу одну большую паутину)))

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

Еще вопрос. Это получается массив чтоли:

y = sorted([ [b-c, a] for a, (b, c) in enumerate(zip(p, ?)) ])[::-1]

А в других комментариях что-нибудь неправильно написал?

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

Непонятно где точка входа. Сначала должна быть функция для чтения srt Похожа на нее

????????????srt.open('srt', encoding='utf-8')
Потом должно быть отделение завершающей строки

На нее похожа:

def ????????(???):
    for i in ???:
        t = i.text.replace('\n', ' ')
        for word in filter(????, t.split(' ')):
            yield word, i
        i.text = []

Потом создание списка слов из сплошной строки Похоже это:

items = list(??????(????, self.sentence.split(' ')))

Верно?

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

Непонятно где точка входа.

Точка входа в python скриптах всегда начало файла. Он (python) последовательно исполняет встречающиеся инструкции. Но скажем инструкция создания функции или определение класса просто добавляет в глобальный/локальный словарь запись с соответствующим именем. Первая строчка (не считая импорты) это:

if __name__ == '__main__':



> Потом должно быть отделение завершающей строки
зачем?

> На нее похожа: 
а тут куча знаков вопроса, я не скажу что это, лучше вынеси эту функцию в отдельный файл и посмотри что она должна делать, попытайся её восстановить.

> Потом создание списка слов из сплошной строки Похоже это: 
создание то создание, но из какой строки?
anonymous ()
Ответ на: комментарий от anonymous

А можете подсказать почему тут два вопросика?

i.text = textwrap.fill(' '.join(i.text), width=??)

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

А как понять 6 вопрос вначале строки:

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

$ cat noise.py

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

Исправленный код.

https://bpaste.net/show/0c2b8db216d5

Как вывести на экран a,b,c в коде:

 y = sorted([
            [b - c, a]
            for a, (b, c) in enumerate(zip(p, x))
        ])[::-1]

Делаю так:

        y = sorted([
            [b - c, a]
            for a, (b, c) in enumerate(zip(p, x)):
                print(a,b,c)
        ])[::-1]
Пишет:
    for a, (b, c) in enumerate(zip(p, x)):
                                         ^
SyntaxError: invalid syntax

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

Как вывести на экран a,b,c в коде:

так:

for a, (b, c) in enumerate(zip(p, x)):
  print(a,b,c)
y = sorted([
  [b - c, a]
  for a, (b, c) in enumerate(zip(p, x))
])[::-1]
а все выражение внутри sorted есть генератор списка, где: [b - c, a] - элемент в списке, for... - цикл для генерации и для этого цикла уже написано тело цикла (элемент в списке)

Упрощенный пример генератора:

print([x*2 for x in range(5)])

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

Понял.

А как соотносится суммирование и цикл?

for a in ??????? - sum(x)):
Если там sum(x), то впереди по идее должно быть то же sum.

Но при суммировании получается одна цифра.

А для цикла нужно последовательность...

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

да, все логично, а может там не sum тогда под знаками вопроса? по какой ещё вещи обычно бывает цикл?

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

Цикл проходит по списку или по другим последовательным обьектам - спискам, например.

Но мне непонятно, там последовательность минусуется суммой.

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

Надо ответить на вопросы:

  • Что такое x и y?
  • Что находится в элементе y[a][1]?
  • Что делает цикл, когда добавляет единицу к элементу x[b]?
anonymous ()
Ответ на: комментарий от anonymous

X:

x = [int(i) for i in p]
Целые числа списка p.

Хотя там по идее долно быть округленные. round 5 букв, а int 3 буквы.

[8, 2] - x in divide

P:

        # p - (количество слов в английском предложении в каждом блоке субтитрах * количество переведенных слов) / (количество слов в английском предложении в каждом блоке субтитрах)
        # p - в сколько раз по количеству слов перевод меньше или больше
        # английских субтитров
        p = [b * n / k for a, b in self.items]
[8.25, 2.75] - p in divide

Т.е. X - это список, по которому мы разделяем переведенный текст. Получается там не int должен быть

chemtech ()
Ответ на: комментарий от chemtech
#!/usr/bin/python3

from random import random

a = [int(100*random()) for i in range(100)]
f = 17/11.
b = [x*f for x in a]
b1 = [int(x) for x in b]
b2 = [round(x) for x in b]

print(sum(b1), sum(b2), sum(a)*f)

Первый элемент в выводе всегда меньше третьего, второй - как повезет.

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

По промежуточным отладкам/итогам:

[8, 2] - x in divide

Y это:

[[0.75, 1], [0.25, 0]]

А y[a][1] это

Второй элемент a-го элемента

т.е. еденица и ноль:

x[1]:

2

x[0]:

8

Часть кода:

        # k - количество слов в английском предложении
        k = sum([b for a, b in self.items])
        print(k, '- k in divide\n')
        p = [b * n / k for a, b in self.items]
        # p - (количество слов в английском предложении в каждом блоке субтитрах * количество переведенных слов) / (количество слов в английском предложении)
        # p - в сколько раз по количеству слов перевод меньше или больше английских субтитров        
        print(p, '- p in divide\n')
        x = [int(i) for i in p]
        print(x, '- x in divide\n')
        # y = sorted([ [b-c, a] for a, (b, c) in enumerate(zip(p, x)) ])[::-1]
        y = sorted([
            [b - c, a]
            for a, (b, c) in enumerate(zip(p, x))
        ])[::-1]
        print(y, ' - y\n')
        for a, (b, c) in enumerate(zip(p, x)):
            print(a,'- a enumerate ',b, '- b enumerate ',c, '- c enumerate \n')
        for a, b in zip(p, x):
            print(a,'- a zip ',b, '- b zip\n')                    
        for a in (sum(y) - sum(x)):
            b = y[a][1]
            x[b] = x[b] + 1

Часть отладки.

12 - k in divide

[8.25, 2.75] - p in divide

[8, 2] - x in divide

[[0.75, 1], [0.25, 0]]  - y

0 - a enumerate  8.25 - b enumerate  8 - c enumerate 

1 - a enumerate  2.75 - b enumerate  2 - c enumerate 

8.25 - a zip  8 - b zip

2.75 - a zip  2 - b zip
chemtech ()
Ответ на: комментарий от chemtech

Да я больше не про цифры спрашивал, а про логический смысл значений в этих элементах. Скажем про x я бы сказал так:

  • x - это список, i-ым элементом которого является количество слов перевода в i-ом элементе субтитров (s).
  • i находится в диапазоне от 0 до n-1.
  • Под переводом следует понимать одно переведенное предложение.
  • s[0] (нулевой элемент субтитров) в данном случае - это первый элемент субтитров по времени, куда требуется записать слова из перевода.
  • s[n-1] - последний элемент по времени, куда требуется записать слова из перевода.
  • n - количество элементов субтитров в которые требуется записать слова из перевода.
  • i, s и n - никак не относится к коду, нужны только для объяснения.
anonymous ()
Ответ на: комментарий от anonymous

Получается примерно так:

x - это список, i-ым элементом которого является количество слов перевода в i-ом элементе субтитров (s).

1
00:00:00,004 --> 00:00:03,293
Welcome to asterisk essentials brought
to you by Digium
 - первый блок srt[0]

2
00:00:03,689 --> 00:00:07,060
The Asterisk company. We're glad that
 - второй блок srt[1]

x = [int(i) for i in p]

Добро пожаловать на уроки Основы Asterisk от Digium, компании создавшей Asterisk.
Всего 11 слов перевода.

Для первого [i = 0] блока x = 8, для второго [i = 1] блока x = 2. Хотя по идее должно быть для второго блока x = 3.

i находится в диапазоне от 0 до n-1.

i количество элементов в списке x или p в скрипте.

Под переводом следует понимать одно переведенное предложение.
s[0] (нулевой элемент субтитров) в данном случае - это первый элемент субтитров по времени, куда требуется записать слова из перевода.

s[0] - это srt[0]

s[n-1] - последний элемент по времени, куда требуется записать слова из перевода.

s[n-1] - это srt[n-1]

n - количество элементов субтитров в которые требуется записать слова из перевода.

n - на сколько элементов субтитров растянулось одно предложение.

??????  for a in ??????? - sum(x)):
            b = y[a][1]
            x[b] = x[b] + 1

Впереди 6 вопросов по идее это просто пробелы. т.к. блок должен начинаться там где for стоит.

Цикл for проходит по какому-то списку.

sum(x) = 10, т.е. sum(x) равно количеству слов в переведенном предложении.

переменная [a] должен быть либо 0 либо 1, но не больше чем n-1.

Дальше разбираю:

b = y[a][1]
x[b] = x[b] + 1
y[0] -	    = [0.75, 1]
y[0][1] - b =	 1
9 	    = x[b] + 1
y[1] -	    = [0.25, 0]
y[1][1] - b =	 0
3 	    = x[b] + 1

Скорее всего там сравнение n (у меня n=11) и sum(x) (у меня sum(x)=10)

Но тут я не вижу сравнение. Тут только вхождение в цикл.

for a in ??????? - sum(x)):

chemtech ()
Последнее исправление: chemtech (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.