Как найти строки одного файла в другом и вывести номер строки совпадения в ruby? - PullRequest
2 голосов
/ 30 июня 2019

У меня есть 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, где присутствует каждая строка.

Формат вывода будет таким:

найти «строку» файла1 | Строка в файле2, где была найдена «строка» файла1 | текст строки в файле2, где была найдена «строка» файла1

Для примера файла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 имеет около 32 тыс. Строк, а настоящий файл2 - около 48 тыс. Строк.

require 'set'

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

Спасибо за любую помощь

UPDATE

Ниже я показываю file1 и file2, предложенные @CarySwoveland, и как будет output для этих входных данных.

enter image description here

UPDATE2

Ниже образцов file1 , file2 и выходных данных file3 .

Ответы [ 2 ]

1 голос
/ 30 июня 2019

Я предполагаю, что каждая строка в файле 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» будет рассматриваться как совпадение до «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
1 голос
/ 30 июня 2019

У проблемы, как указано, нет правильного решения, потому что нет никакого способа объяснить 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"]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...