Многоуровневый анализ текста

В прошлый раз у меня возникла проблема: парсинг и структурирование текстового файла. Теперь я представляю сложные условия. Например. У меня был текстовый файл со следующим содержанием:

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
Другие вопросы по тегам