【问题标题】:Ruby script issueRuby脚本问题
【发布时间】:2018-06-17 17:28:41
【问题描述】:

我正在尝试创建一个 ruby​​ 脚本,但我正在为如何继续而苦苦挣扎。

我的脚本的目标是,从 2 个字幕文件中,我想通过将第一个文件的时间与第二个文件的字幕相结合来制作第三个文件。

不知道我说清楚了没有,基本上我的2个字幕文件一样,只是版本不同,即相同序列的时间可能不同。 p>

这是想要的结果:

# File One : Version KILLERS (English) 

1
00:00:01,874 --> 00:00:05,577
<i>Previously on "12 Monkeys"...</i>

2
00:00:05,625 --> 00:00:07,882
- Did Marion send you?
- Who?

3
00:00:07,938 --> 00:00:09,905
Marion, the boy's mother.

# File Two : Version AMZN (Translated in French)

1
00:00:08,140 --> 00:00:11,850
<i>Précédemment...</i>

2
00:00:12,260 --> 00:00:14,120
- C'est Marion qui vous envoie ?
- Qui ?

3
00:00:14,150 --> 00:00:16,110
Marion, sa mère.

# File Three : Objective -> Getting a KILLERS versions for French subtitles

1
00:00:01,874 --> 00:00:05,577
<i>Précédemment...</i>

2
00:00:05,625 --> 00:00:07,882
- C'est Marion qui vous envoie ?
- Qui ?

3
00:00:07,938 --> 00:00:09,905
Marion, sa mère.

我们可以为时间分配变量“time”(例如00:00:07,938),为文本分配变量“text”。

因此,我想用第二个文件中的时间替换第一个文件中的每个“时间线”。

这是我尝试过的:

#!/usr/bin/ruby -w

#To run the script : ./script.rb TVshowENG.srt TVshowESP.srt NewTVshow.srt


def time_srt (h, m, s, ms)
   t = h + ":" + m + ":" + s + "," + ms
end

File.open(ARGV[0], 'r') do |file_one|
    File.open(ARGV[1], 'r') do |file_two|
       File.open(ARGV[2], 'w') do |file_out|
           file_one.each_line do |line|
               if line.strip =~ /^(\d{2}):(\d{2}):(\d{2}),(\d{3})\D+(\d{2}):(\d{2}):(\d{2}),(\d{3})$/
                   file_out << time_srt($1, $2, $3, $4) + ' --> ' +
                                time_srt($5, $6, $7, $8) + "\n"
               else
                   file_out << line # I want to print line from file_two there
               end
           end
       end
    end
end 

编辑:最终脚本随机故障

1 - 脚本运行问题:脚本运行,突然停止并出现此错误

./SyncScript.rb:25:in `block (4 levels) in <main>': invalid byte sequence in UTF-8 (ArgumentError)
    from ./SyncScript.rb:18:in `loop'
    from ./SyncScript.rb:18:in `block (3 levels) in <main>'
    from ./SyncScript.rb:17:in `open'
    from ./SyncScript.rb:17:in `block (2 levels) in <main>'
    from ./SyncScript.rb:16:in `open'
    from ./SyncScript.rb:16:in `block in <main>'
    from ./SyncScript.rb:15:in `open'
    from ./SyncScript.rb:15:in `<main>'

2- 故障(关于#的更多详细信息)

14    # From 1 to 16, it worked perfectly fine)
00:00:38,535 --> 00:00:40,832
Elle est revenue !

15
00:00:49,746 --> 00:00:51,620
<i>Ce que je vais te dire</i>

16
00:00:51,715 --> 00:00:54,749
<i>est la légende telle
que l'on me l'a racontée.</i>

00:01:01,650 --> 00:01:04,190  # Suddently, there's no sequence number (here, 17)
<i>Il y avait autrefois un serpent</i>

00:01:04,300 --> 00:01:06,870  # Same here (no 18)
<i>qui n'allait
que dans une seule direction.</i>
19   # Yet, there is 19. But no space ('\n' issue)
00:01:07,150 --> 00:01:10,740
<i>Toujours en avant, jamais en arrière.</i>
20  # Same...
00:01:11,020 --> 00:01:13,080
<i>Jusqu'au jour où,</i>
21
00:01:13,260 --> 00:01:16,770
<i>le serpent tomba sur un démon.</i>
22
00:01:21,670 --> 00:01:22,730
Stop !
23
00:01:38,050 --> 00:01:40,050
Ho ! Ho !
24
00:01:59,030 --> 00:02:01,090
Je suis sûr que vous ne serez pas
surpris d'apprendre que
25
00:02:01,130 --> 00:02:04,310
nous avons vu votre venue

26
00:02:06,380 --> 00:02:11,020  #No subtitles there ??

27
00:02:11,690 --> 00:02:13,390

【问题讨论】:

  • 你说,“这是我试过的”。我们是否假设它没有产生预期的结果?你真的需要一个例子。我建议您提供两个字符串来显示这两个文件的内容,以及第三个字符串来显示您希望生成的文件的内容。为前两个字符串中的每一个分配一个变量会很有帮助(例如,str1 = "..."str2 ="...")。通过这样做,读者可以剪切和粘贴并在 cmets 和答案中引用这些变量,而无需定义它们。输入文件只需几行(越少越好)。
  • 你在哪里说,“因此,我想替换每一个……”,你不是倒过来了吗?
  • 我从翻译文件中得到它,但不是复制/粘贴时间,而是脚本会这样做。大约有 400 多个序列/集:D
  • 我的意思是你不想用 first 文件中的时间替换 second 文件中的每个“时间线”吗?跨度>
  • 这很重要,因为它是问题陈述的一部分;它解释了你想做什么。

标签: ruby


【解决方案1】:

你有几个问题。

  1. 您的正则表达式与整行不匹配,您需要添加 (\D+) 以说明数字后面的短语。
  2. 您希望同时循环遍历这两个文件;这很容易通过使用loop dogets 来完成。

通过这两个修复,您的代码可以正常工作:

File.open(ARGV[0], 'r') do |file_one|
    File.open(ARGV[1], 'r') do |file_two|
        File.open(ARGV[2], 'w') do |file_out|
            loop do
                line_one = file_one.gets
                line_two = file_two.gets
                break unless line_one and line_two #gets gives nil at EOF
                if line_one.strip =~ /^(\d{2}):(\d{2}):(\d{2}),(\d{3})\D+(\d{2}):(\d{2}):(\d{2}),(\d{3})$/
                    temp = time_srt($1, $2, $3, $4) + ' --> ' +
                        time_srt($5, $6, $7, $8) #take time from line_one
                    if line_two.strip =~ /^(\d{2}):(\d{2}):(\d{2}),(\d{3})\D+(\d{2}):(\d{2}):(\d{2}),(\d{3})$/
                        file_out << temp + "\n" + file_two.gets #take phrase from file_two
                        file_one.gets #skip phrase in file_one
                    end
                else
                    file_out << line_two #Keep file_two's lines when not a timestamp
                end
            end
        end
    end
end

使用您的示例文件进行测试会产生:

1
00:00:01,874 --> 00:00:05,577
<i>Précédemment...</i>

2
00:00:05,625 --> 00:00:07,882
- C'est Marion qui vous envoie ?
- Qui ?

3
00:00:07,938 --> 00:00:09,905
Marion, sa mère.

【讨论】:

  • 注意: 这将仅排除第一个文件中的时间戳行,而不是第二个文件中的时间戳行。如果您想保留它们,您还需要在嵌套的 if 上添加一个 else
  • 完美!它工作得很好。非常感谢 !对不起,我还不熟悉这个网站,谢谢你的评论。
  • 你好,又是我。该脚本有效,但我碰巧遇到随机故障。我用小故障编辑了我的问题。
  • @JohnDoe 可能是因为我在上面的第一条评论中所说的^,除了时间之外,你的两个文件在每一行都相同吗?尝试将else 块添加到内部if 也只是将line_two 打印到file_out
  • 时间和语言不同(但含义相同,nb of line...)。好的,我稍后再试,我会回来提供一些消息:)
【解决方案2】:

这是一种更类似于 Ruby 的方式来执行所需的替换。

代码

def substitute(french_fname, english_fname)
  r = /^\d{2}:\d{2}:\d{2},\d{3} --> \d{2}:\d{2}:\d{2},\d{3}$/
  english_lines = File.read(ENGLISH_FNAME).scan(r)
  File.read(FRENCH_FNAME).gsub(r) { english_lines.shift }
end

示例

这是您使用 Heredocs 编写的两个文件的内容。 (搜索“此处文档”here.

english =<<IGNOMINIOUS_END
1
00:00:01,874 --> 00:00:05,577
<i>Previously on "12 Monkeys"...</i>

2
00:00:05,625 --> 00:00:07,882
- Did Marion send you?
- Who?

3
00:00:07,938 --> 00:00:09,905
Marion, the boy's mother.
IGNOMINIOUS_END

french =<<BITTER_END
1
00:00:08,140 --> 00:00:11,850
<i>Précédemment...</i>

2
00:00:12,260 --> 00:00:14,120
- C'est Marion qui vous envoie ?
- Qui ?

3
00:00:14,150 --> 00:00:16,110
Marion, sa mère.
BITTER_END

现在让我们创建两个文件,我将其命名为“english”和“french”。

ENGLISH_FNAME = "english"
FRENCH_FNAME  = "french"

File.write(ENGLISH_FNAME, english)
  #=> 191
File.write(FRENCH_FNAME, french)
  #=> 182

我们现在可以使用方法substitute 来计算根据需要修改的法语文件的内容(字符串,当然可以写入文件)。

puts substitute(french_fname, english_fname)
1
00:00:01,874 --> 00:00:05,577
<i>Précédemment...</i>

2
00:00:05,625 --> 00:00:07,882
- C'est Marion qui vous envoie ?
- Qui ?

3
00:00:07,938 --> 00:00:09,905
Marion, sa mère.

说明

如果这两个文件很大,人们会想逐行阅读它们,但可以合理地假设它们的大小相当适中(即使电影的运行时间是 1,000 小时),所以我会将它们成字符串。

english_content = File.read(ENGLISH_FNAME)
french_content  = File.read(FRENCH_FNAME)

查看IO#read 并回想File.superclass #=&gt; IO

接下来,让我们使用 String#scan 和正则表达式从 english_content 中提取 substitutor 行的数组。

r = /^\d{2}:\d{2}:\d{2},\d{3} --> \d{2}:\d{2}:\d{2},\d{3}$/

english_lines = english_content.scan(r)
  #=> ["00:00:01,874 --> 00:00:05,577",
  #    "00:00:05,625 --> 00:00:07,882",
  #    "00:00:07,938 --> 00:00:09,905"]

注意"^""$"行首行尾 锚,不要与字符串开始混淆em> ("\A") 和 end-of-string ("\z") 锚。

最后,我们使用 String#gsub 方法和相同的正则表达式来执行所需的替换。

french_content.gsub(r) { english_lines.shift }

【讨论】:

  • 哇,这很复杂 x)。我会努力学习的,谢谢!
  • 其实,逐个检查每个步骤并没有那么复杂。仔细阅读,你会学到很多东西。
  • 现在复杂得多了。
  • 好的,我开始明白了,我用代码发布答案,询问一些细节:)
  • 要运行它,只需执行substitute(french_fname, english_fname),将两个参数替换为您的实际文件名。
猜你喜欢
  • 2016-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-16
  • 1970-01-01
  • 2016-01-05
相关资源
最近更新 更多