如何在另一个文件中搜索一个文件的字符串并在ruby中打印匹配项的行号?

时间:2019-06-30 06:45:44

标签: ruby

我有这2个文件:

file1

Ruby
C
Visual Basic
R
Objective-C
Basic
HTML

file2

5. ab cde fg Java hij kl
2. ab PHP dddf llf 
4. cde fg z o Objective-C oode
8. a12b cde JavaScript kdk
6. ab99r cde Visual Basic llso dkd
1. lkd dsk Ruby kksdk
3. Python dsdls
7. kdjd C jdjd
9. CSS dkdsk
7. kkd Basic jjs
3. rooor R kdk

我想搜索文件1中的字符串,如果在文件2中找到它们,然后打印“文件1的字符串”,然后打印文件2中的行号以及其中存在每个字符串的文件2的行。 / p>

输出格式如下:

找到文件1的“字符串” |找到文件1的“字符串”的文件2中的行|在file2中找到file1的“字符串”的行文本

对于示例文件1和文件2,我正在寻找的输出是:

Ruby|6|1. lkd dsk Ruby kksdk
C|8|7. kdjd C jdjd
Visual Basic|5|6. ab99r cde Visual Basic llso dkd
R|11|3. rooor R kdk
Objective-C|3|4. cde fg z o Objective-C oode
Basic|10|7. kkd Basic jjs
HTML|Not found

我尝试了以下代码,但没有找到任何东西。我的真实文件1大约有32K行,真实文件2大约有48K行。

require 'set'

f2_set = File.readlines("file2.txt").map(&:chomp).to_set
File.foreach("file1.txt") { |line| puts line if f2_set.include?(line) }

感谢您的帮助

更新

下面,我展示了@CarySwoveland提出的file1file2,以及这些输入的output会如何。

enter image description here

UPDATE2

file1file2的样本下面并输出file3

2 个答案:

答案 0 :(得分:1)

指出的问题没有正确的解决方案,因为没有办法解释Ruby Basic(匹配器列表中最后一个元素旁边)匹配行6.时不考虑 。需要更复杂的规则集才能完成所需的操作。

但这将是一个很好的起点:

matchers = File.readlines("file1.txt")
lines = File.readlines("file2.txt")

matchers.inject([]) do |acc, match|
  acc | lines.each.with_index(1).map do |line, idx|
    [match, idx, line].join("|") if line =~ /\b(#{match}\b)/
  end.compact
end
#⇒ ["Ruby|6|1. lkd dsk Ruby kksdk",
#   "C|3|4. cde fg z o Objective-C oode",
#   "C|8|7. kdjd C jdjd",
#   "Visual Basic|5|6. ab99r cde Visual Basic llso dkd",
#   "R|11|3. rooor R kdk",
#   "Objective-C|3|4. cde fg z o Objective-C oode",
#   "Basic|5|6. ab99r cde Visual Basic llso dkd",
#   "Basic|10|7. kkd Basic jjs"]

答案 1 :(得分:1)

我假设文件1的每一行最多出现在文件2的每一行中,文件2的每一行在文件1中包含的语言不超过一种,这与问题中给出的示例一致。

首先构造文件。为了使生活更有趣,我修改了问题中给出的两个文件的内容。

file1 =<<-END
Ruby
C
Visual Basic
C++
R
Objective-C++
Basic
HTML
END

FName1 = 'file1'
File.write(FName1, file1)
  #=> 51

file2 =<<-END
5. ab cde fg Java hij kl
2. ab PHP dddf llf 
4. cde fg z o Objective-C++ oode
8. a12b cde JavaScript kdk
6. ab99r cde Visual Basic llso dkd
1. lkd dsk Ruby kksdk
3. Python dsdls
7. kdjd C jdjd
9. CSS dkdsk
10. blah C++ blah
7. kkd Basic jjs
3. rooor R kdk
END

FName2 = 'file2'
File.write(FName2, file2)
  #=> 256

首先将FName1的行读入数组。

languages = File.readlines(FName1, chomp:true)
  #=> ["Ruby", "C", "Visual Basic", "C++",
  #    "R", "Objective-C++", "Basic", "HTML"]  

现在,为方便起见,将languages的元素的长度减小。

sorted_languages = languages.sort_by(&:length).reverse
  #=> ["Objective-C++", "Visual Basic", "Basic",
  #    "Ruby", "HTML", "C++", "C", "R"] 

我已经通过减小字长来对languages的元素进行了排序,以便在尝试将FName2的行与'Objective-C ++'进行匹配之前进行尝试C ++”和“ C ++”将在“ C”之前考虑。同样,在考虑“基本”之前,“ Visual Basic”将被视为匹配项。

接下来,创建一个哈希,其键是FName1中出现在FName2行中的行,其值是散列,用于标识给定行FName2中的行号和行键。

language_to_file2 = File.foreach(FName2, chomp: true).
  with_index(1).
  with_object({}) do |(line,n),h|
    language = sorted_languages.find { |language| line.include?(language) }
    h[language] = { line: line, nbr: n } unless language.nil?
  end
  #=> {"Objective-C++"=>{:line=>"4. cde fg z o Objective-C++ oode", :nbr=>3},
  #    "Visual Basic" =>{:line=>"6. ab99r cde Visual Basic llso dkd", :nbr=>5},
  #    "Ruby"         =>{:line=>"1. lkd dsk Ruby kksdk", :nbr=>6},
  #    "C"            =>{:line=>"7. kdjd C jdjd", :nbr=>8},
  #    "C++"          =>{:line=>"10. blah C++ blah", :nbr=>10},
  #    "Basic"        =>{:line=>"7. kkd Basic jjs", :nbr=>11},
  #    "R"            =>{:line=>"3. rooor R kdk", :nbr=>12}}

我们现在可以显示所需的结果。

languages.each do |language|
  print "#{language}|"
  if language_to_file2.key?(language)
    h = language_to_file2[language]
    puts "%d|%s" % [h[:nbr], h[:line]]
  else
    puts "Not found"
  end
end
Ruby|6|1. lkd dsk Ruby kksdk
C|8|7. kdjd C jdjd
Visual Basic|5|6. ab99r cde Visual Basic llso dkd
C++|10|10. blah C++ blah
R|12|3. rooor R kdk
Objective-C++|3|4. cde fg z o Objective-C++ oode
Basic|11|7. kkd Basic jjs
HTML|Not found