好的,这就是我最终想出的。我相信它应该对你有用,具有以下实现:
- 如果每个文件的当前行以可解析的日期开头,则最早的获胜(将第 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