Class: AtCoderFriends::FormatParser
- Inherits:
-
Object
- Object
- AtCoderFriends::FormatParser
- Defined in:
- lib/at_coder_friends/format_parser.rb
Overview
parses input data format and generates input definitons
Constant Summary collapse
- PARSERS =
[ { container: :harray, item: :number, pat: /^(?<v>[a-z]+)[01](\s+\k<v>.)*(\s+\.+)?(\s+\k<v>.)+$/i, names: ->(m) { [m[:v]] }, pat2: ->(_) { nil }, size: ->(f) { [f[-1]] } }, { container: :harray, item: :char, pat: /^(?<v>[a-z]+)[01](\k<v>.)*(\s*\.+\s*)?(\k<v>.)+$/i, names: ->(m) { [m[:v]] }, pat2: ->(_) { nil }, size: ->(f) { [f[-1]] } }, { container: :matrix, item: :number, pat: /^(?<v>[a-z]+)[01][01](\s+\k<v>..)*(\s+\.+)?(\s+\k<v>..)+$/i, names: ->(m) { [m[:v]] }, pat2: ->(v) { /(^#{v}..(\s+#{v}..)*(\s+\.+)?(\s+#{v}..)+|\.+)$/ }, size: ->(f) { f[-2..-1].chars.to_a } }, { container: :matrix, item: :char, pat: /^(?<v>[a-z]+)[01][01](\k<v>..)*(\s*\.+\s*)?(\k<v>..)+$/i, names: ->(m) { [m[:v]] }, pat2: ->(v) { /(^#{v}..(#{v}..)*(\s*\.+\s*)?(#{v}..)+|\.+)$/ }, size: ->(f) { f[-2..-1].chars.to_a } }, { container: :varray, item: :number, pat: /^[a-z]+(?<i>[0-9])(\s+[a-z]+\k<i>)*$/i, names: ->(m) { m[0].split.map { |w| w[0..-2] } }, pat2: lambda { |vs| pat = vs.map { |v| v + '.+' }.join('\s+') /^(#{pat}|\.+)$/ }, size: ->(f) { /(?<sz>\d+)$/ =~ f ? [sz] : [f[-1]] } }, { container: :single, item: :number, pat: /^[a-z]+(\s+[a-z]+)*$/i, names: ->(m) { m[0].split }, pat2: ->(_) { nil }, size: ->(_) { [] } } ].freeze
Instance Method Summary collapse
- #match_smp!(inpdefs, smp) ⇒ Object
-
#max_smp(smps) ⇒ Object
rubocop:enable Metrics/MethodLength, Metrics/AbcSize.
- #parse(fmt, smps) ⇒ Object
-
#parse_fmt(lines) ⇒ Object
rubocop:disable Metrics/MethodLength, Metrics/AbcSize.
- #process(pbm) ⇒ Object
- #split_trim(fmt) ⇒ Object
Instance Method Details
#match_smp!(inpdefs, smp) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/at_coder_friends/format_parser.rb', line 139 def match_smp!(inpdefs, smp) lines = smp.split("\n") inpdefs.each_with_index do |inpdef, i| break if i > lines.size next if inpdef.item != :number inpdef.item = :string if lines[i].split[0] =~ /[^\-0-9]/ break if %i[varray matrix].include?(inpdef.container) end inpdefs end |
#max_smp(smps) ⇒ Object
rubocop:enable Metrics/MethodLength, Metrics/AbcSize
132 133 134 135 136 137 |
# File 'lib/at_coder_friends/format_parser.rb', line 132 def max_smp(smps) smps .select { |smp| smp.ext == :in } .max_by { |smp| smp.txt.size } &.txt end |
#parse(fmt, smps) ⇒ Object
83 84 85 86 87 88 89 90 |
# File 'lib/at_coder_friends/format_parser.rb', line 83 def parse(fmt, smps) lines = split_trim(fmt) defs = parse_fmt(lines) smpx = max_smp(smps) return defs unless smpx match_smp!(defs, smpx) end |
#parse_fmt(lines) ⇒ Object
rubocop:disable Metrics/MethodLength, Metrics/AbcSize
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/at_coder_friends/format_parser.rb', line 106 def parse_fmt(lines) it = Iterator.new(lines + ['']) # sentinel prv = nil cur = it.next Enumerator.new do |y| loop do unless (parser = PARSERS.find { |ps| ps[:pat] =~ cur }) puts "unknown format: #{cur}" unless cur.empty? (cur = it.next) ? next : break end container, item = parser.values_at(:container, :item) m = parser[:pat].match(cur) names = parser[:names].call(m) pat2 = parser[:pat2].call(names) loop do prv = cur cur = it.next break unless pat2 && pat2 =~ cur end size = parser[:size].call(prv) y << InputDef.new(container, item, names, size) end end.to_a end |
#process(pbm) ⇒ Object
78 79 80 81 |
# File 'lib/at_coder_friends/format_parser.rb', line 78 def process(pbm) defs = parse(pbm.fmt, pbm.smps) pbm.defs = defs end |
#split_trim(fmt) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/at_coder_friends/format_parser.rb', line 92 def split_trim(fmt) fmt .gsub(/[+-]1/, '') # N-1, N+1 -> N .gsub(%r{[-/ ]}, ' ') # a-b, a/b -> a b .gsub(/\{.*?\}/) { |w| w.delete(' ') } # {1, 1} -> {1,1} shortest match .gsub(/[_,'\\(){}]/, '') .gsub(/[::…‥]+/, '..') .gsub(/ldots/, '..') .gsub(/^[.\s]+$/, '..') .split("\n") .map(&:strip) end |