2015-06-29 3 views
0

Мой собственный маленький проект состоит в объединении двух журналов на основе временных меток, оба журнала имеют одну и ту же метку времени. Некоторые строки не имеют временных меток и должны быть напечатаны с помощью строки с меткой времени.Как выполнить итерацию по двум массивам в отдельности

так что если у меня есть журналы, как это:

2015-06-25 09:20:25,654 file1 text2 
2015-06-25 09:20:23,654 file1 text1 
test text1 belongs to the row above 
2015-06-25 09:20:27,654 file1 text3 

А другой файл является таким же образом, но с различными временными метками. Поскольку я новичок в Ruby, я обнаружил, что этот проект может быть хорошим началом.

До сих пор я нашел достаточно помощи, что я должен использовать счетчики, и я предполагаю, что в

loop do 
    code 
end 

Но как я решу, когда я хочу итерацию file1 file2 без буду перебирать тоже? И как узнать, когда один итератор находится в конце файла, чтобы я мог распечатать остальную часть другого файла?

Должен ли я сначала прочитать файлы для каждого массива или просто выполнить два потока для каждого файла и один поток в выходной файл?

summary: Я хочу выполнить итерацию по двум файлам, пока один файл не достигнет конца, а затем напечатайте последние строки в другом файле и получив контроль над тем, когда итерация произойдет в обоих файлах.

Спасибо за ваше время и ввод!

** Edit: **

Но я хочу, чтобы объединить их вместе с временными метками. Как:
2015-06-25 09: 20: 24123 file1 text1

2015-06-25 09: 20: 23123 file2 text1
2015-06-25 09: 20: 26123 file2 text2

Выход:
2015-06-25 09: 20: 23123 file2 text1
2015-06-25 09: 20: 24123 file1 text1
2015-06-25 09: 20: 26123 file2 text2

Основном если У меня есть два массива, которые я перебираю с помощью итератора x и y. Если x> y, тогда поместите y в выходной файл и сделайте как y ++, затем продолжайте проверять их против eachother до конца файла. Если x равно eof, просто добавьте остальную часть y в выходной файл.

+0

Вы можете проверить, если вы находитесь в конце вашего потока входного файла, используя [ВФ?] (http://ruby-doc.org/core-2.2.2/IO.html#method-i-eof -3F). Насколько известно, когда вы хотите читать из файла 1 или 2, это сводится к вашим требованиям. Мне трудно понять, что вы имеете в виду, когда говорите «затем распечатывайте последние строки в другом файле». Если бы вы могли уточнить, что я мог бы предоставить пример кода в ответе. – Brandon

+0

Итак, журналы используют один и тот же синтаксис. дате информации о времени в нормальном состоянии Log4j, а иногда есть stacktrace с и нет даты в начале строки. Итак, когда я перебираю два файла и объединяя их с большим одиночным выходным файлом, я хочу взять все данные, оставшиеся в файле2, и просто нажимать все на выходной файл, если file1 достигает его адресата или файла2, поскольку я знаю метка времени выше, потому что ее eof в файле1. Надеюсь, что что-то прояснит. – Lundell

+0

Насколько велики файлы? Это самая большая проблема, которую я вижу с этим, так как им нужно будет как поместиться в памяти. – Brandon

ответ

0

Хорошо, вот что я в итоге придумал. Я считаю, что он должен работать для вас, со следующей реализацией:

  • Если текущая строка из каждого файла начинается с синтаксический анализируемым днем, то самые старые победы (изменить < на линии 49, чтобы > поменять что) ,
  • Когда строка выводится на выход, файл, из которого была прочитана строка, циклически перемещается, и следующая строка захватывается. Строка из другого файла остается неизменной до тех пор, пока эта строка не будет написана.
  • Если строка не начинается с синтаксической даты, эта строка выигрывает и записывается. Как указано выше, этот файл циклически перемещается, и следующая строка втягивается, повторяясь до тех пор, пока не будет снова разобрана синтаксическая дата или не будет удалена в конец файла.
  • Если один из файлов достигнет своего конца, другой файл будет передан на выход до тех пор, пока он не достигнет своего выхода.

Пожалуйста, обратите внимание, что вам нужно будет изменить 'file1', 'file2' и 'output' в файл путей, относительных или абсолютных. Вы можете использовать ARGV или OptionParser, чтобы использовать аргументы командной строки для передачи этих данных в программу.

Входные файлы:

# file1 

2014-06-21 07:20:25,654 file1 text2 
2015-01-13 14:24:23,654 file1 text1 
test text1 belongs to the row above 
2015-06-21 08:57:27,654 file1 text3 

# file2 

2013-01-05 19:27:25,654 file1 text2 
2015-04-01 10:13:23,654 file1 text1 
test text5 belongs to the row above 
2015-06-23 09:49:27,654 file1 text3 

# output 

2013-01-05 19:27:25,654 file1 text2 
2014-06-21 07:20:25,654 file1 text2 
2015-01-13 14:24:23,654 file1 text1 
test text1 belongs to the row above 
2015-04-01 10:13:23,654 file1 text1 
test text5 belongs to the row above 
2015-06-21 08:57:27,654 file1 text3 
2015-06-23 09:49:27,654 file1 text3 

# compile_files.rb 

require 'date' 

# Attempt to read a line from the supplied file. 
# If this fails, we are at the end of the file and return nil. 
def read_line_from_file(file) 
    file.readline 
rescue EOFError 
    nil 
end 

# Parse the date which is at the beginning of the supplied text. 
# If this fails, it doesn't start with a date so we return nil. 
def parse_date(text) 
    DateTime.parse(text) 
rescue ArgumentError 
    nil 
end 

begin 
    # Open the files to sort 
    input_file_1 = File.open('file1', 'r') 
    input_file_2 = File.open('file2', 'r') 

    # Open the file that will be written. Here it is named "output" 
    File.open('output', 'w+') do |of| 
    # Read the first line from each file 
    left = read_line_from_file(input_file_1) 
    right = read_line_from_file(input_file_2) 

    # Loop until BOTH files have reached their end 
    until left.nil? && right.nil? 
     # If the first file was successfully read, 
     # attempt to parse the date at the beginning of the line 
     left_date = parse_date(left) if left 
     # If the second file was successfully read, 
     # attempt to parse the date at the beginning of the line 
     right_date = parse_date(right) if right 

     # If the first file was successfully read, 
     # but the date was not successfully parsed, 
     # the line is a stack trace and needs to be printed 
     # because it will be following the related 
     # timestamped line. 
     if left && left_date.nil? 
     of << left 

     # Now that we have printed that line, 
     # grab the next one from the same file. 
     left = read_line_from_file(input_file_1) 
     next 

     # If the first file was successfully read, 
     # but the date was not successfully parsed, 
     # the line is a stack trace and needs to be printed 
     # because it will be following the related 
     # timestamped line. 
     elsif right && right_date.nil? 
     of << right 

     # Now that we have printed that line, 
     # grab the next one from the same file. 
     right = read_line_from_file(input_file_2) 

     # Skip straight to the next iteration of the `until` loop. 
     next 
     end 

     if left.nil? 
     of << right 

     # Now that we have printed that line, 
     # grab the next one from the same file. 
     right = read_line_from_file(input_file_2) 

     # Skip straight to the next iteration of the `until` loop. 
     next 
     end 

     # If we got this far, neither of the lines were stack trace 
     # lines. If the second file has reached its end, we need 
     # to print the line we grabbed from the first file. 
     if right.nil? 
     of << left 

     # Now that we have printed that line, 
     # grab the next one from the same file. 
     left = read_line_from_file(input_file_1) 

     # Skip straight to the next iteration of the `until` loop. 
     next 
     end 

     # ADDED THIS SECTION 
     # If we got this far, the second file has not 
     # reached its end. If the first file has reached 
     # its end, we need to print the line we grabbed 
     # from the second file. 
     if left.nil? 
     of << right 

     # Now that we have printed that line, 
     # grab the next one from the same file. 
     right = read_line_from_file(input_file_2) 

     # Skip straight to the next iteration of the `until` loop. 
     next 
     end 

     # If we got this far, neither file has reached its 
     # end and both start with timestamps. If the first file's 
     # timestamp is less, it is older. 
     if left_date < right_date 
     of << left 

     # Now that we have printed that line, 
     # grab the next one from the same file. 
     left = read_line_from_file(input_file_1) 

     # Skip straight to the next iteration of the `until` loop. 
     next 
     # Either the timestamps were the same or the second one is 
     # older. 
     else 
     of << right 

     # Now that we have printed that line, 
     # grab the next one from the same file. 
     right = read_line_from_file(input_file_2) 

     # Skip straight to the next iteration of the `until` loop. 
     next 
     end 
    end 
    end 
ensure 
    # Make sure that the file descriptors are close. 
    input_file_1.close 
    input_file_2.close 
end 
+0

см. Мое редактирование выше – Lundell

+0

Помог ли вам ответ? – Brandon

+0

Извините за позднюю реакцию, у вас есть кое-что, о чем нужно позаботиться. Поэтому мой вывод показывает это только как результат. Не отсортировано вообще. Когда вы говорите: если left && left_date.nil? Мне нравится идея с "до left.nil? && right.nil?" потому что это заставит оба файла идти до конца. Но дата синтаксического анализа? Что ты там делал? Я делаю это так. если оставить [my_regex] и кажется намного проще вместо синтаксического анализа дат. Но так как сейчас я не сортирую его. Но я попытаюсь изменить некоторые вещи в вашем коде. Большое спасибо! – Lundell

Смежные вопросы