我建议从哈希开始,像翻译表一样使用它。哈希查找非常快,并且可以很好地组织您的标签及其替换。
hash = {
# old_tag => new_tag
'C#' => 'C-Sharp',
'C Sharp' => 'C-Sharp',
'Crazy' => '',
'C #' => 'C-Sharp',
}
您可以看到值中有很多冗余,可以通过反转哈希来修复,这可以很好地减少它:
hash = {
# new_tag => old_tag
'C-Sharp' => ['C#', 'C Sharp', 'C #'],
}
'Crazy'
是一个异常值,但我们会处理它。
RubyString.gsub
有一个很好但很少使用的特性,我们可以向它传递一个正则表达式和一个散列,它会将所有正则表达式匹配替换为散列中的等效值。我们可以轻松构建该正则表达式:
regex = /(?:#{ Regexp.union(hash.keys).source })/
=> /(?:C\-Sharp)/
现在,您可能会说,“但是等等,我还有很多标签要查找!”,并且由于哈希的构建方式,它们隐藏在值中。为了解决这个问题,我们将反转散列的键和值,将值数组分解为它们各自的元素:
reversed_hash = Hash[hash.flat_map{ |k,v| v.map{ |i| [i,k] } }]
=> {
"C#" => "C-Sharp",
"C Sharp" => "C-Sharp",
"C #" => "C-Sharp",
}
通过合并“特殊情况”的第二个散列,添加'Crazy'
很容易:
special_cases = {
'Crazy' => ''
}
reversed_hash = Hash[hash.flat_map{ |k,v| v.map{ |i| [i,k] } }].merge(special_cases)
=> {
"C#" => "C-Sharp",
"C Sharp" => "C-Sharp",
"C #" => "C-Sharp",
"Crazy" => ""
}
将其与正则表达式构建代码一起使用:
regex = /(?:#{ Regexp.union(reversed_hash.keys).source })/
=> /(?:C\#|C\ Sharp|C\ \#|Crazy)/
这将使用自动生成的正则表达式找到标签。如果需要不区分大小写,请使用:
regex = /(?:#{ Regexp.union(reversed_hash.keys).source })/i
创建一些文本进行测试:
text =<<EOT
This is "#C#"
This is "C Sharp"
This is "C #"
This is "Crazy"
EOT
=> "This is \"#C#\"\nThis is \"C Sharp\"\nThis is \"C #\"\nThis is \"Crazy\"\n"
并测试gsub
:
puts text.gsub(regex, reversed_hash)
哪个输出:
This is "#C-Sharp"
This is "#C-Sharp"
This is "#C-Sharp"
This is "#"
现在,我不喜欢将大文件放入内存中,因为这不能很好地扩展。今天的机器通常有许多 GB 的内存,但我看到文件仍然超过机器中的 RAM。因此,File.read
我gsub
建议使用File.foreach
. 使用它会更改代码。
这是我的做法:
file_to_read = '/path/to/file/to/read'
File.open(file_to_read + '.new', 'w') do |fo|
File.foreach(file_to_read) do |li|
fo.puts li.gsub(regex, reversed_hash)
end
end
File.rename(file_to_read, file_to_read + '.bak')
File.rename(file_to_read + '.new', file_to_read)
这将为每个处理的文件创建一个 .bak 版本,因此如果出现问题,您有一个备用方案,这始终是一个好习惯。
编辑:我忘记了 CSV 文件:
您可以使用 CSV 模块使用 Ruby 轻松读取/创建一个,但是我会使用 YAML 文件,因为它允许您在易于手动编辑或从文件生成的文件中轻松创建哈希布局。
编辑:更多关于 CSV、YAML 和从另一个生成一个
以下是如何读取 CSV 并将其转换为推荐的哈希格式:
require 'csv'
text = <<EOT
C#, C-Sharp
C Sharp, C-Sharp
Crazy,
C #, C-Sharp
EOT
hash = Hash.new{ |h,k| h[k] = [] }
special_cases = []
CSV.parse(text) do |k,v|
(
(v.nil? || v.strip.empty?) ? special_cases : hash[v.strip]
) << k.strip
end
从之前捡起:
reversed_hash = Hash[hash.flat_map{ |k,v| v.map{ |i| [i,k] } }].merge(Hash[special_cases.map { |k| [k, ''] }])
puts reversed_hash
# => {"C#"=>"C-Sharp", "C Sharp"=>"C-Sharp", "C #"=>"C-Sharp", "Crazy"=>""}
要将 CSV 文件转换为更可编辑和更有用的文件,请使用上面的代码创建hash
and special_cases
,然后:
require 'yaml'
puts ({
'hash' => hash,
'special_cases' => special_cases
}).to_yaml
看起来像:
---
hash:
C-Sharp:
- C#
- C Sharp
- ! 'C #'
special_cases:
- Crazy
其余的你可以从 YAML 文档中找到。