ebook_tools 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ 0.0.1 2013.4.1
2
+ init release
data/README ADDED
@@ -0,0 +1,76 @@
1
+ # encoding: UTF-8
2
+ # = ExtractBookStruct
3
+ # ExtractBookStruct的目的是从各类电子书内容中提取书的结构信息。目前支持txt,epub,html。
4
+ # ExtractBookStruct选择从TXT文档提取书的结构信息。对TXT的文档要有如下要求:
5
+ # 1. 文档的编码格式必须是UTF-8或GB2312,推荐使用UTF-8格式
6
+ # 2. 文档的内容只包含书内容部分(书名、作者、目录等信息应该不包含在文档内)
7
+ # 3. 文档的段落应该完整(有些PDF转换过来的文档会破坏句子,需要进行预处理)
8
+ # 4. 文档必须符合正常的文档流(错位的章节段落等情况将影响正常的结构提取)
9
+ # 5. 文档需要包含结构信息(例如: 卷、篇、部分、章(回)节或者有连续的序号)
10
+ # 6. 每个结构信息都应该独立成行。
11
+ #
12
+ # 文档结构信息分析
13
+ # 一本书在编排的时候会有自己的结构信息,这些结构信息通常通过卷、篇、部分、章(回)节等表述,也会使用序号的方式表述。总体上可以分为以下几种:
14
+ # 1. 文本描述(text): 按卷、部分(篇)、章(回)、节等文字表述
15
+ # 2. 数字描述(digital): 所有结构信息都是按照数字序号表示,比如 1 xxxxx; 1.1 xxxxx
16
+ # 3. 混合描述(hybrid):章按照文字表述,节按照序号表示,比如 1.1 xxxxxx
17
+ # 根据不同的类型,对结构信息的提取采用不同的处理手段。
18
+ #
19
+ # 有效的标题信息应该符合以下规则:
20
+ # 1. 标题应该不包含完整的句子(应该不包含句子分隔符,例如“。","!"等)
21
+ # 2. 应该包含结构信息表述,具体如下:
22
+ # 文本描述:
23
+ # 卷: 以"第xxx卷"开始
24
+ # 以"卷"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
25
+ # 以"volume"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
26
+ # 部分(篇): 以"第xxx部"或"第xxx篇"开始
27
+ # 以"part"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
28
+ # 章(回): 以"第xxx章"或"第xxx回"开始
29
+ # 以"chapter"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
30
+ # 节: 以"第xxx节"开始
31
+ # 前言: 以"前"开始,以"言"结束,中间加入空白字符。例如"前言","前 言"等。
32
+ # 以"序"开始,以"言"结束,中间加入空白字符。例如"序言","序 言"等。
33
+ # 单个"序"
34
+ # 以"序"或"序言"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
35
+ # "preface"
36
+ # "foreword"
37
+ # 以"preface"或"foreword"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
38
+ # 索引: 以"索"开始,以"引"结束,中间加入空白字符。例如"索引","索 引"等。
39
+ # 以"索引"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
40
+ # "index"
41
+ # 以"index"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
42
+ # 附录: 以"附"开始,以"录"结束,中间加入空白字符。例如"附录","附 录"等。
43
+ # 以"附录"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
44
+ # "appendix"
45
+ # 以"appendix"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
46
+ # 术语: 以"术"开始,以"语"结束,中间加入空白字符。例如"术语","术 语"等。
47
+ # 以"术语"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
48
+ # "glossary"
49
+ # 以"glossary"开始,后面跟序号表述方式,例如 “I”,“Ⅱ”,“1”等
50
+ #
51
+ # 数字描述:
52
+ # 以数字序号层级表达,数字序号和标题内容之间有空白字符分隔。例如"1 管理的概念", "1.1 定义", "1.1.1 管理"等。
53
+ #
54
+ # ==API接口
55
+ #
56
+ # === ExtractBookStruct.from_txt
57
+ # 从文本文件中提取目录结构,使用示例:
58
+ # ExtractBookStruct.from_txt('1.txt',{:title=>'title',:author=>'author'})
59
+ #
60
+ # === ExtractBookStruct.from_epub
61
+ # 从EPUB文件中提取目录结构,使用示例:
62
+ # ExtractBookStruct.from_epub('1.epub',{:title=>'title',:author=>'author'})
63
+ #
64
+ # === ExtractBookStruct.from_html
65
+ # 从HTML中提取目录结构,使用示例:
66
+ # ExtractBookStruct.from_html('1.html',{:title=>'title',:author=>'author'})
67
+ #
68
+ # == 命令行工具
69
+ # extract_book_struct,使用示例:
70
+ # extract_book_struct '1.txt', '1.xml'
71
+ #
72
+ # == 依赖
73
+ # ExtractBookStruct依赖以下工具和包:
74
+ # ebook-convert: calibre cli tools.
75
+ # uuid: ruby gem.
76
+ # iconv: ruby gem.
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require File.join(File.expand_path('../../',__FILE__),'lib','ebook_tools')
6
+
7
+
8
+ def help(command=nil)
9
+ case command
10
+ when :convert
11
+ puts <<-EOF
12
+ usage:
13
+ ebook_tools convert [options] source destination
14
+
15
+ source: 源文件
16
+ destination: 输出的文件
17
+
18
+ options:
19
+ -K <keywords>, --keywords <keywords> : 当需要给epub打关键词时使用该参数。
20
+ -F, --fix : 当需要自动修复异常中断的句子时使用该参数
21
+ --length : 每行的长度,当需要自动修复异常中断的句子时使用该参数。
22
+ -H <row_count>, --header <row_count> : 仅对pdf文件有效,当需要指定页眉行数时使用该参数。
23
+ --footer <row_count> : 仅对pdf文件有效,当需要指定页脚行数时使用该参数。
24
+ EOF
25
+ when :batch_convert
26
+ puts <<-EOF
27
+ usage:
28
+ ebook_tools batch_convert [options] source destination
29
+
30
+ source: 源文件所在目录
31
+ destination: 输出的目标目录
32
+
33
+ options:
34
+ -K <keywords>, --keywords <keywords> : 当需要给epub打关键词时使用该参数。
35
+ -F, --fix : 当需要自动修复异常中断的句子时使用该参数
36
+ -H <row_count>, --header <row_count> : 仅对pdf文件有效,当需要指定页眉行数时使用该参数。
37
+ --footer <row_count> : 仅对pdf文件有效,当需要指定页脚行数时使用该参数。
38
+ EOF
39
+ when :extract
40
+ puts <<-EOF
41
+ usage:
42
+ ebook_tools extract [options] source destination
43
+
44
+ source: 指定需要提取结构信息的书文件
45
+ destination: 指定提取的书结构信息所输出的文件
46
+
47
+ options:
48
+ -T <title>, --title <title> : 书的标题
49
+ -A <author>, --author <author> : 书作者
50
+ --pubdate <pubdate> : 出版时间
51
+ --publisher <publisher> : 出版社
52
+ EOF
53
+ when :batch_extract
54
+ puts <<-EOF
55
+ usage:
56
+ ebook_tools batch_extract source destination
57
+
58
+ source: 源文件所在目录
59
+ destination: 输出的目标目录
60
+ EOF
61
+ when :paras_repair
62
+ puts <<-EOF
63
+ usage:
64
+ ebook_tools paras_repair [options] source destination
65
+
66
+ source: 指定需要修复段落的源文件,必须是文本文件
67
+ destination: 指定修复后输出的文件
68
+
69
+ options:
70
+ -l <length>, --length <length> : 指定异常段落被截断的最小长度。
71
+ EOF
72
+ else
73
+ puts <<-EOF
74
+ ebook_tools: ebook处理工具集,包括格式转换,结构提取等。
75
+ usage:
76
+ ebook_tools command [options] source destination
77
+
78
+ command:
79
+ convert: 从source文件格式转换成epub格式,source文件支持txt,html,epub,pdf格式
80
+ extract: 从source文件中提取书结构信息
81
+ paras_repair: 对文本文件进行段落修复
82
+ batch_convert: 批量转换指定目录中的文件为epub格式文件,并存放到目标目录
83
+ batch_extract: 批量提取指定目录中文件的书结构信息,并生成Docbook存放到目标目录
84
+
85
+ 适用对象要求:
86
+ 编码格式为utf-8
87
+
88
+ 具体命令的更多信息请通过'ebook_tools help <command>'查看。
89
+ EOF
90
+ end
91
+
92
+ exit
93
+ end
94
+
95
+ def extract_argv(argv)
96
+ argv = argv.dup
97
+ command = argv.shift
98
+ source = argv[-2]
99
+ destination = argv[-1]
100
+ [command,source,destination,argv]
101
+ end
102
+
103
+ command,source,destination,opt_args = extract_argv(ARGV)
104
+
105
+ options = {}
106
+ opts = OptionParser.new do |opts|
107
+ opts.on('-F','--fix') do |fix|
108
+ options[:fix] = fix
109
+ end
110
+
111
+ opts.on('-H row_count','--header row_count') do |row_count|
112
+ options[:header_rows_count] = row_count.to_i
113
+ end
114
+
115
+ opts.on('--footer row_count') do |row_count|
116
+ options[:footer_rows_count] = row_count.to_i
117
+ end
118
+
119
+ opts.on('-K keywords','--keywords keywords') do |keywords|
120
+ options[:keywords] = keywords
121
+ end
122
+
123
+ opts.on('-L length','--length length') do |length|
124
+ options[:length] = length.to_i
125
+ end
126
+
127
+ opts.on('-T title','--title title','title') do |title|
128
+ options[:title] = title
129
+ end
130
+
131
+ opts.on('-A author','--author author','author') do |author|
132
+ options[:author] = author
133
+ end
134
+
135
+ opts.on('--publisher publisher','publisher') do |publisher|
136
+ options[:publisher] = publisher
137
+ end
138
+
139
+ opts.on('--pubdate pubdate','pubdate') do |pubdate|
140
+ options[:pubdate] = pubdate
141
+ end
142
+
143
+ opts.on('-h','--help') do
144
+ help
145
+ end
146
+ end
147
+ opts.parse opt_args
148
+ command = command.to_sym if command
149
+
150
+ if source.nil? || destination.nil?
151
+ help(command)
152
+ end
153
+
154
+ unless Utils.source_exists?(source)
155
+ puts "error: source #{source} no found"
156
+ exit
157
+ end
158
+
159
+ begin
160
+ Utils.make_destination_dir(destination)
161
+ rescue
162
+ puts "error: destination #{destination} not created"
163
+ exit
164
+ end
165
+
166
+ begin
167
+ case command
168
+ when :convert
169
+ if EbookTools.convert(source,destination,options)
170
+ puts "success: #{source} conversion successfully!"
171
+ else
172
+ puts "error: 只允许转换txt,html,pdf,epub格式"
173
+ end
174
+ when :batch_convert
175
+ EbookTools.batch_convert(source,destination,options)
176
+ when :extract
177
+ if EbookTools.allow_extract_struct?(source)
178
+ if EbookTools.extract_book_struct_to_file(source,destination,options)
179
+ puts "success: extract book struct successfully!"
180
+ else
181
+ puts "警告: 没有检测到书结构信息."
182
+ end
183
+ else
184
+ puts "error: #{source}不是允许的文件格式: txt,html,epub"
185
+ end
186
+ when :batch_extract
187
+ EbookTools.batch_extract_from_dir(source,destination,options)
188
+ when :paras_repair
189
+ EbookTools.text_paras_repair(source,destination,options)
190
+ puts "success: #{source} repair successfully!"
191
+ else
192
+ help
193
+ end
194
+ rescue => e
195
+ puts "error: #{source} \n#{e.backtrace.join("\n")}"
196
+ end
@@ -0,0 +1,38 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{ebook_tools}
5
+ s.version = '0.0.1'
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Aaron"]
9
+ s.date = %q{2013-04-01}
10
+ s.description = %q{电子书工具集.}
11
+ s.email = %q{aaron@nonobo.com}
12
+ s.require_paths = ["lib"]
13
+ s.requirements = ["none"]
14
+ s.summary = %q{电子书工具集.}
15
+ s.has_rdoc = true
16
+ s.rdoc_options = ["--charset=UTF-8"]
17
+ s.executables << "ebook_tools"
18
+ s.files = [
19
+ "README",
20
+ "CHANGELOG",
21
+ "bin/ebook_tools",
22
+ "lib/ebook_tools.rb",
23
+ "lib/extract_book_struct.rb",
24
+ "lib/header_detect.rb",
25
+ "lib/pdf.rb",
26
+ "lib/txt.rb",
27
+ "lib/epub.rb",
28
+ "lib/utils.rb",
29
+ "ebook_tools.gemspec"
30
+ ]
31
+ s.add_dependency(%q<uuid>)
32
+ s.add_dependency(%q<iconv>)
33
+ s.add_dependency(%q<gepub>)
34
+ s.add_dependency(%q<poppler>)
35
+ s.add_dependency(%q<pdf-reader>)
36
+ s.add_dependency(%q<nokogiri>)
37
+ s.add_dependency(%q<levenshtein>)
38
+ end
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ ['utils','epub','txt','pdf','header_detect','extract_book_struct'].each do |file|
4
+ require File.join(File.dirname(__FILE__),file)
5
+ end
6
+
7
+ module EbookTools
8
+ extend self
9
+
10
+ def convert(filename,epub_file,options={})
11
+ method_name = "#{File.extname(filename).gsub('.','')}2epub"
12
+ if EbookTools.respond_to?(method_name)
13
+ EbookTools.send(method_name,filename,epub_file,options)
14
+ return true
15
+ else
16
+ return nil
17
+ end
18
+ end
19
+
20
+ # txt2epub
21
+ # 将文本格式转换成EPUB格式
22
+ def txt2epub(filename,epub_file,options={})
23
+ basename = File.basename(filename,'.txt')
24
+ temp_dir = "#{basename}"
25
+ FileUtils.mkdir(temp_dir) unless File.exists?(temp_dir)
26
+
27
+ title,outlines, content = TXT.extract_book_part(filename)
28
+
29
+ if options[:fix]
30
+ content = Utils.fixed_page_break(content)
31
+ end
32
+
33
+ html_content = TXT.gen_html_from_txt_book(title,outlines,content)
34
+ html = Utils.wrapper_html(html_content)
35
+
36
+ html_file = File.join([temp_dir,"#{basename}.html"].compact)
37
+ Utils.write_file(html,html_file)
38
+ sections = Utils.detect_sections_from_html(html_file)
39
+
40
+ nav_file = EPUB.gen_nav_file(html_file,sections)
41
+
42
+ EPUB.write_epub(epub_file,options.merge(:files=>[nav_file,html_file]))
43
+ ensure
44
+ FileUtils.remove_dir(temp_dir,true)
45
+ end
46
+
47
+ # html2epub
48
+ # 将HTML格式转换成EPUB格式
49
+ def html2epub(filename,epub_file,options={})
50
+ basename = File.basename(filename,'.html')
51
+ temp_dir = "#{basename}"
52
+ FileUtils.mkdir(temp_dir) unless File.exists?(temp_dir)
53
+
54
+ html = File.open(filename).read
55
+
56
+ html_file = File.join([temp_dir,"#{basename}.html"].compact)
57
+ Utils.write_file(html,html_file)
58
+ sections = Utils.detect_sections_from_html(html_file)
59
+
60
+ nav_file = EPUB.gen_nav_file(html_file,sections)
61
+
62
+ EPUB.write_epub(epub_file,options.merge(:files=>[nav_file,html_file]))
63
+ ensure
64
+ FileUtils.remove_dir(temp_dir,true)
65
+ end
66
+
67
+ # pdf2epub
68
+ # 将PDF格式转换成EPUB格式
69
+ def pdf2epub(filename,epub_file,options={})
70
+ basename = File.basename(filename,'.pdf')
71
+ temp_dir = "#{basename}"
72
+ FileUtils.mkdir(temp_dir) unless File.exists?(temp_dir)
73
+
74
+ pages_text = PDF.extract_pdf_pages_text(filename)
75
+ pages_text = PDF.sanitize_page_header_and_footer(pages_text,options)
76
+ pages_text = PDF.fixed_break_with_pages_text(pages_text)
77
+
78
+ sections = PDF.extract_sections(filename)
79
+
80
+ illustrations = PDF.extract_illustrations(filename,{:dir=>temp_dir})
81
+
82
+ html_content = PDF.gen_html_from_sections_and_page_texts(sections,pages_text,illustrations)
83
+ html = Utils.wrapper_html(html_content)
84
+ html_file = File.join([temp_dir,"#{basename}.html"].compact)
85
+ Utils.write_file(html,html_file)
86
+
87
+ illustrations_path = illustrations.map{|image_path| File.join(temp_dir,image_path)}
88
+
89
+ nav_file = EPUB.gen_nav_file(html_file,sections)
90
+
91
+ files = [html_file,nav_file,illustrations_path].flatten
92
+
93
+ meta = PDF.extract_pdf_meta(filename)
94
+ epub_options = options.merge(meta).merge(:files=>files)
95
+
96
+ EPUB.write_epub(epub_file,epub_options)
97
+
98
+ ensure
99
+ FileUtils.remove_dir(temp_dir,true)
100
+ end
101
+
102
+ def batch_convert(source,destination,options={})
103
+ log = File.open('batch.log','a')
104
+ success_log = File.open('success.log','a')
105
+ error_log = File.open('error.log','a')
106
+ scan_log = File.open('scan.log','a')
107
+ unknown_log = File.open('unknown.log','a')
108
+
109
+ source_path = File.absolute_path(source)
110
+ dest_path = File.join(File.absolute_path(destination),'epub')
111
+ scan_path = File.join(File.absolute_path(destination),'scan')
112
+ unknown_path = File.join(File.absolute_path(destination),'unknown')
113
+ backup_path = File.join(File.absolute_path(destination),'backup')
114
+
115
+ format = options[:format]
116
+
117
+ files = Utils.scan_file_from_dir(source_path,:format=>format)
118
+
119
+ total_count = files.count
120
+ scan_count = 0
121
+ success_count = 0
122
+ error_count = 0
123
+ unknown_count = 0
124
+
125
+ puts "count: #{total_count} file "
126
+ log.puts "****batch convert****** : #{Time.now}"
127
+ log.puts "#{source_path} => #{dest_path} "
128
+ log.puts "count: #{total_count} file "
129
+
130
+ success_log.puts "****batch convert****** : #{Time.now}"
131
+ success_log.puts "#{source_path} => #{dest_path} "
132
+
133
+ error_log.puts "****batch convert****** : #{Time.now}"
134
+ error_log.puts "#{source_path} => #{dest_path} "
135
+
136
+ scan_log.puts "****batch convert****** : #{Time.now}"
137
+ scan_log.puts "#{source_path} => #{dest_path} "
138
+
139
+ unknown_log.puts "****batch convert****** : #{Time.now}"
140
+ unknown_log.puts "#{source_path} => #{dest_path} "
141
+
142
+
143
+ files.each do |file|
144
+ dest_file = File.join(File.dirname(File.join(dest_path,file.gsub(source_path,''))),"#{File.basename(file,File.extname(file))}.epub")
145
+
146
+ keywords = Utils.extract_keywords_from_path(File.dirname(file).gsub(source_path,''))
147
+ puts "start convert #{file}"
148
+
149
+ method_name = "#{File.extname(file).gsub('.','')}2epub"
150
+ if EbookTools.respond_to?(method_name)
151
+ begin
152
+ if PDF.scan_pdf?(file)
153
+ scan_file = File.join(scan_path,file.gsub(source_path,''))
154
+ FileUtils.mkdir_p(File.dirname(scan_file)) unless Dir.exists?(File.dirname(scan_file))
155
+ FileUtils.mv(file,scan_file,:force=>true)
156
+ scan_count += 1
157
+ scan_log.puts "warning: #{file} is scan pdf."
158
+ else
159
+ EbookTools.send(method_name,file,dest_file,{:keywords=>keywords})
160
+ success_file = File.join(backup_path,file.gsub(source_path,''))
161
+ FileUtils.mkdir_p(File.dirname(success_file)) unless Dir.exists?(File.dirname(success_file))
162
+ FileUtils.mv(file,success_file,:force=>true)
163
+ success_count += 1
164
+ success_log.puts "success: #{source} conversion successfully!"
165
+ end
166
+ rescue Exception => e
167
+ unknown_file = File.join(unknown_path,file.gsub(source_path,''))
168
+ FileUtils.mkdir_p(File.dirname(unknown_file)) unless Dir.exists?(File.dirname(unknown_file))
169
+ FileUtils.mv(file,unknown_file,:force=>true)
170
+ error_count += 1
171
+ error_log.puts "error: #{source} \n#{e.backtrace.join("\n")}"
172
+ end
173
+ end
174
+ end
175
+
176
+ success_log.puts "count: #{success_count} Time: #{Time.now} \n"
177
+ scan_log.puts "count: #{scan_count} Time: #{Time.now} \n"
178
+ error_log.puts "count: #{error_count} Time: #{Time.now} \n"
179
+ unknown_log.puts "unknown: #{unknown_count} Time: #{Time.now} \n"
180
+ log.puts "success: #{success_count} scan: #{scan_count} error: #{error_count} Time: #{Time.now} \n"
181
+
182
+ ensure
183
+ success_log.close
184
+ error_log.close
185
+ scan_log.close
186
+ unknown_log.close
187
+ log.close
188
+ end
189
+
190
+ def allow_extract_struct?(file)
191
+ extname = File.extname(file)
192
+ ['.txt','.html','.epub'].include?(extname.downcase)
193
+ end
194
+
195
+ def extract_book_struct_to_file(source,destination,options={})
196
+ method_name = "from_#{File.extname(source).gsub('.','')}"
197
+ if ExtractBookStruct.respond_to?(method_name)
198
+ docbook_xml = ExtractBookStruct.send(method_name,source,options)
199
+ if docbook_xml
200
+ File.open(destination,'wb'){|file|file.write docbook_xml}
201
+ return true
202
+ else
203
+ return nil
204
+ end
205
+ end
206
+ end
207
+
208
+ # batch_extract_from_dir
209
+ # batch extract book struct form dir
210
+ # parameters:
211
+ # +source+ source directory
212
+ # +destination+ output directory
213
+ # +options+ optional parameter.
214
+ # :format 指定需要提取结构的文件后缀名,例如要从所有txt文件中提取,通过:format=>'.txt'指定
215
+ def batch_extract_from_dir(source,destination,options={})
216
+ format = options.delete(:format)
217
+ files = Utils.scan_file_from_dir(source,{:format=>format})
218
+
219
+ files.each do |file|
220
+ extname = File.extname(file)
221
+ basename = File.basename(file,extname)
222
+ dest_file = File.join(File.dirname(File.join(destination,file.gsub(source,''))),"#{basename}.xml")
223
+ if allow_extract_struct?(file)
224
+ puts "start extract #{file} ..."
225
+ begin
226
+ if extract_book_struct_to_file(file,dest_file)
227
+ puts "success: extract book struct successfully!"
228
+ else
229
+ puts "警告: 没有检测到书结构信息."
230
+ end
231
+ rescue Exception => e
232
+ puts "error: #{file} \n#{e.backtrace.join("\n")}"
233
+ end
234
+ else
235
+ puts "error: #{file}不是允许的文件格式: txt,html,epub"
236
+ end
237
+ end
238
+ end
239
+
240
+ # text_paras_repair
241
+ # 对文本文件格式中的中断段落进行修复
242
+ def text_paras_repair(source_file,target_file,options={})
243
+ content = File.open(source_file).read
244
+ content = Utils.to_utf8 unless Utils.detect_utf8(content)
245
+ content = Utils.fixed_page_break(content,options)
246
+ File.open(target_file,'w'){|file| file.write content}
247
+ end
248
+ end