Module: AtCoderFriends::Parser::InputType

Defined in:
lib/at_coder_friends/parser/input_type.rb

Overview

parses input data types and updates input definitons

Constant Summary collapse

NUMBER_PAT =
/\A[+-]?[0-9]{1,19}\z/.freeze
DECIMAL_PAT =
/\A[+-]?[0-9]{1,19}(\.[0-9]+)?\z/.freeze
TYPE_TBL =
[
  [:number, NUMBER_PAT],
  [:decimal, DECIMAL_PAT]
].freeze

Class Method Summary collapse

Class Method Details

.detect_col_type(arr) ⇒ Object



83
84
85
86
87
88
89
# File 'lib/at_coder_friends/parser/input_type.rb', line 83

def detect_col_type(arr)
  ret = :string
  TYPE_TBL.any? do |type, pat|
    arr.all? { |v| v =~ pat } && ret = type
  end
  ret
end

.detect_cols_type(rows) ⇒ Object



74
75
76
77
# File 'lib/at_coder_friends/parser/input_type.rb', line 74

def detect_cols_type(rows)
  cols = fill_transpose(rows).map(&:compact)
  cols.map { |col| detect_col_type(col) }
end

.fill_transpose(arr) ⇒ Object



79
80
81
# File 'lib/at_coder_friends/parser/input_type.rb', line 79

def fill_transpose(arr)
  Array.new(arr.map(&:size).max) { |i| arr.map { |e| e[i] } }
end

.get_line_cnt(inpdef) ⇒ Object



49
50
51
52
53
54
55
56
57
58
# File 'lib/at_coder_friends/parser/input_type.rb', line 49

def get_line_cnt(inpdef)
  case inpdef.size.size
  when 0
    1
  when 1
    inpdef.container == :harray ? 1 : inpdef.size[0]
  when 2
    inpdef.size[0]
  end
end

.match_smp(inpdefs, lines) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/at_coder_friends/parser/input_type.rb', line 32

def match_smp(inpdefs, lines)
  vars = {}
  inpdefs.each do |inpdef|
    break unless  (k = get_line_cnt(inpdef))

    k, parsed = parse_line_cnt(k, vars)
    rows = lines.shift(k).map { |line| line.split(/[#{inpdef.delim} ]/) }
    break if rows.empty?

    inpdef.container == :single &&
      vars.merge!(inpdef.names.zip(rows[0]).to_h)
    inpdef.cols = detect_cols_type(rows)
    break unless parsed
  end
  inpdefs
end

.max_smp(smps) ⇒ Object



25
26
27
28
29
30
# File 'lib/at_coder_friends/parser/input_type.rb', line 25

def max_smp(smps)
  smps
    .select { |smp| smp.ext == :in }
    .max_by { |smp| smp.txt.size }
    &.txt
end

.parse(inpdefs, smps) ⇒ Object



20
21
22
23
# File 'lib/at_coder_friends/parser/input_type.rb', line 20

def parse(inpdefs, smps)
  lines = max_smp(smps)&.split("\n")
  lines && match_smp(inpdefs, lines)
end

.parse_line_cnt(k, vars) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/at_coder_friends/parser/input_type.rb', line 60

def parse_line_cnt(k, vars)
  if k.is_a?(Integer)
    [k, true]
  elsif k =~ NUMBER_PAT
    [k.to_i, true]
  elsif vars[k] =~ NUMBER_PAT
    [vars[k].to_i, true]
  elsif vars[(k2 = k.gsub(/-1\z/, ''))] =~ NUMBER_PAT
    [vars[k2].to_i - 1, true]
  else
    [1, false]
  end
end

.process(pbm) ⇒ Object



16
17
18
# File 'lib/at_coder_friends/parser/input_type.rb', line 16

def process(pbm)
  parse(pbm.formats_src, pbm.samples)
end