Ниже приведено чистое решение Ruby. Я предполагаю, что скобки и скобки в строке сбалансированы.
str =<<BITTER_END
Some infobox royalty|testing
| name = Louis
| title = Prince Napoléon
| elevation_imperial_note= <ref name="usgs">{{cite web|url={{Gnis3|1802764}}|title=USGS}}</ref>
| a = [[AA|aa]] | b = {{cite
|title=TITLE
|author=AUTHOR}}
BITTER_END
stack = []
last = 0
str.each_char.with_index.with_object([]) do |(c,i),locs|
puts "c=#{c}, i=#{i}, locs=#{locs}, stack=#{stack}"
case c
when ']', '}'
puts " pop #{c} from stack"
stack.pop
when '[', '{'
puts " push #{c} onto stack"
stack << c
when '|'
puts stack.empty? ? " record location of #{c}" : " skip | as stack is non-empty"
locs << i if stack.empty?
end
puts " after: locs=#{locs}, stack=#{stack}"
end.map do |i|
old_last = last
last = i+1
str[old_last..i-1].strip if i > 0
end.tap { |a| a << str[last..-1].strip if last < str.size }
#=> ["Some infobox royalty",
# "testing",
# "name = Louis",
# "title = Prince Napoléon",
# "elevation_imperial_note= <ref name=\"usgs\">
# {{cite web|url={{Gnis3|1802764}}|title=USGS}}</ref>",
# "a = [[AA|aa]]",
# "b = {{cite\n|title=TITLE\n|author=AUTHOR}}"]
Обратите внимание, что для улучшения читабельности я разбил строку, которая является предпоследним элементом возвращаемого массива 1 .
Объяснение
Для объяснения того, как определяются местоположения символов канала, по которым определяется разделение, запустите Heredoc выше, чтобы определить str
(Heredoc должен быть сначала без отступа), а затем выполните следующий код. Все будет раскрыто. (Вывод длинный, поэтому обратите внимание на изменения в массивах locs
и stack
.)
stack = []
str.each_char.with_index.with_object([]) do |(c,i),locs|
puts "c=#{c}, i=#{i}, locs=#{locs}, stack=#{stack}"
case c
when ']', '}'
puts " pop #{c} from stack"
stack.pop
when '[', '{'
puts " push #{c} onto stack"
stack << c
when '|'
puts stack.empty? ? " record location of #{c}" : " skip | as stack is non-empty"
locs << i if stack.empty?
end
puts " after: locs=#{locs}, stack=#{stack}"
end
#=> [20, 29, 44, 71, 167, 183]
При желании можно подтвердить, что скобки и скобки сбалансированы следующим образом.
def balanced?(str)
h = { '}'=>'{', ']'=>'[' }
stack = []
str.each_char do |c|
case c
when '[', '{'
stack << c
when ']', '}'
stack.last == h[c] ? (stack.pop) : (return false)
end
end
stack.empty?
end
balanced?(str)
#=> true
balanced?("[[{]}]")
#=> false
1 ... и, в интересах прозрачности, иметь возможность использовать определенное слово .