Многоуровневый анализ текста
В прошлый раз у меня возникла проблема: парсинг и структурирование текстового файла. Теперь я представляю сложные условия. Например. У меня был текстовый файл со следующим содержанием:
Head 1
Subhead 1
a 10
b 14
c 88
Subhead 2
a 15
b 16
c 17
d 88
Subhead 3
a 55
b 36
c 87
Head 4
Subhead 1
r 32
t 55
s 79
r 22
t 88
y 53
o 78
p 90
m 44
Head 53
Subtitle 1
y 22
b 33
Subtitle 2
a 88
g 43
r 87
Head 33
Subhead 1
z 11
d 66
v 88
b 69
Head 32
Subhead 1
n 88
m 89
b 88
Subhead 2
b 88
m 43
Теперь мне нужно структурировать текст на следующую плоскость. Я хочу получить следующие данные:
Head 1, Subhead 1, c 88
Head 1, Subhead 2, d 88
Head 4, Subhead 1, t 88
Head 53, Subhead 2, a 88
Head 33, Subhead 1, v 88
Head 32, Subhead 1, n 88
Head 32, Subhead 1, b 88
Head 32, Subhead 2, b 88
То есть я хочу получить все строки с 88, указывающими голову и подзаголовок.
Мои действия:
lines = File.open("file.txt").to_a
lines.map!(&:chomp) # remove line breaks
current_head = ""
res = []
lines.each do |line|
case line
when /Head \d+/
current_head = line
when /Subhead/
sub = line
when /\w{1} 88/
num = line
res << "#{current_head}, #{sub}, #{num}"
end
end
puts res
Когда я использую этот метод, я получаю строку без значений NUM.
Возможно ли выполнить мою задачу означает "случай, когда" возможно?
2 ответа
Переменные, объявленные внутри each
блок не сохраняется между итерациями. Когда итерация заканчивается, эти переменные исчезают, поэтому вы теряете предыдущую sub
значение. Чтобы исправить это, переместите sub
переменная во внешнюю область, инициализируя ее перед each
так же, как у вас с current_head
:
current_head = ""
current_sub = ""
res = []
lines.each do |line|
case line
when /Head \d+/
current_head = line
when /Subhead/
current_sub = line
when /\w{1} 88/
num = line
res << "#{current_head}, #{current_sub}, #{num}"
end
end
Смотрите его на repl.it: https://repl.it/GBKn
Если вы хотите сохранить переменные между двумя итерациями, вы можете использовать переменные экземпляра.
File.foreach
рекомендуемый способ чтения файла:
res = []
File.foreach("file.txt") do |line|
line.chomp!
case line
when /Head \d+/
@current_head = line
when /Sub(head|title)/
@sub = line
when /\w 88/
num = line
res << "#{@current_head}, #{@sub}, #{num}"
end
end
puts res