Class: Csvlint::Csvw::NumberFormat
- Inherits:
-
Object
- Object
- Csvlint::Csvw::NumberFormat
- Defined in:
- lib/csvlint/csvw/number_format.rb
Instance Attribute Summary collapse
-
#decimal_separator ⇒ Object
readonly
Returns the value of attribute decimal_separator.
-
#fractional_grouping_size ⇒ Object
readonly
Returns the value of attribute fractional_grouping_size.
-
#grouping_separator ⇒ Object
readonly
Returns the value of attribute grouping_separator.
-
#integer ⇒ Object
readonly
Returns the value of attribute integer.
-
#numeric_part ⇒ Object
readonly
Returns the value of attribute numeric_part.
-
#pattern ⇒ Object
readonly
Returns the value of attribute pattern.
-
#prefix ⇒ Object
readonly
Returns the value of attribute prefix.
-
#primary_grouping_size ⇒ Object
readonly
Returns the value of attribute primary_grouping_size.
-
#secondary_grouping_size ⇒ Object
readonly
Returns the value of attribute secondary_grouping_size.
-
#suffix ⇒ Object
readonly
Returns the value of attribute suffix.
Instance Method Summary collapse
-
#initialize(pattern = nil, grouping_separator = nil, decimal_separator = ".", integer = nil) ⇒ NumberFormat
constructor
A new instance of NumberFormat.
- #match(value) ⇒ Object
- #parse(value) ⇒ Object
Constructor Details
#initialize(pattern = nil, grouping_separator = nil, decimal_separator = ".", integer = nil) ⇒ NumberFormat
Returns a new instance of NumberFormat.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/csvlint/csvw/number_format.rb', line 6 def initialize(pattern = nil, grouping_separator = nil, decimal_separator = ".", integer = nil) @pattern = pattern @integer = integer if @integer.nil? @integer = if @pattern.nil? nil else !@pattern.include?(decimal_separator) end end @grouping_separator = grouping_separator || (@pattern.nil? ? nil : ",") @decimal_separator = decimal_separator || "." if pattern.nil? @regexp = if integer INTEGER_REGEXP else Regexp.new("^(([-+]?[0-9]+(\\.[0-9]+)?([Ee][-+]?[0-9]+)?[%‰]?)|NaN|INF|-INF)$") end else numeric_part_regexp = Regexp.new("(?<numeric_part>[-+]?([0#Ee]|#{Regexp.escape(@grouping_separator)}|#{Regexp.escape(@decimal_separator)})+)") number_format_regexp = Regexp.new("^(?<prefix>.*?)#{numeric_part_regexp}(?<suffix>.*?)$") match = number_format_regexp.match(pattern) raise Csvw::NumberFormatError, "invalid number format" if match.nil? @prefix = match["prefix"] @numeric_part = match["numeric_part"] @suffix = match["suffix"] parts = @numeric_part.split("E") mantissa_part = parts[0] exponent_part = parts[1] || "" mantissa_parts = mantissa_part.split(@decimal_separator) # raise Csvw::NumberFormatError, "more than two decimal separators in number format" if parts.length > 2 integer_part = mantissa_parts[0] fractional_part = mantissa_parts[1] || "" if ["+", "-"].include?(integer_part[0]) numeric_part_regexp = "\\#{integer_part[0]}" integer_part = integer_part[1..-1] else numeric_part_regexp = "[-+]?" end min_integer_digits = integer_part.gsub(@grouping_separator, "").delete("#").length min_fraction_digits = fractional_part.gsub(@grouping_separator, "").delete("#").length max_fraction_digits = fractional_part.gsub(@grouping_separator, "").length min_exponent_digits = exponent_part.delete("#").length max_exponent_digits = exponent_part.length integer_parts = integer_part.split(@grouping_separator)[1..-1] @primary_grouping_size = begin integer_parts[-1].length rescue 0 end @secondary_grouping_size = begin integer_parts[-2].length rescue @primary_grouping_size end fractional_parts = fractional_part.split(@grouping_separator)[0..-2] @fractional_grouping_size = begin fractional_parts[0].length rescue 0 end if @primary_grouping_size == 0 integer_regexp = "[0-9]*[0-9]{#{min_integer_digits}}" else leading_regexp = "([0-9]{0,#{@secondary_grouping_size - 1}}#{Regexp.escape(@grouping_separator)})?" secondary_groups = "([0-9]{#{@secondary_grouping_size}}#{Regexp.escape(@grouping_separator)})*" if min_integer_digits > @primary_grouping_size remaining_req_digits = min_integer_digits - @primary_grouping_size req_secondary_groups = (remaining_req_digits / @secondary_grouping_size > 0) ? "([0-9]{#{@secondary_grouping_size}}#{Regexp.escape(@grouping_separator)}){#{remaining_req_digits / @secondary_grouping_size}}" : "" if remaining_req_digits % @secondary_grouping_size > 0 final_req_digits = "[0-9]{#{@secondary_grouping_size - (remaining_req_digits % @secondary_grouping_size)}}" final_opt_digits = "[0-9]{0,#{@secondary_grouping_size - (remaining_req_digits % @secondary_grouping_size)}}" integer_regexp = "((#{leading_regexp}#{secondary_groups}#{final_req_digits})|#{final_opt_digits})[0-9]{#{remaining_req_digits % @secondary_grouping_size}}#{Regexp.escape(@grouping_separator)}#{req_secondary_groups}[0-9]{#{@primary_grouping_size}}" else integer_regexp = "(#{leading_regexp}#{secondary_groups})?#{req_secondary_groups}[0-9]{#{@primary_grouping_size}}" end else final_req_digits = (@primary_grouping_size > min_integer_digits) ? "[0-9]{#{@primary_grouping_size - min_integer_digits}}" : "" final_opt_digits = (@primary_grouping_size > min_integer_digits) ? "[0-9]{0,#{@primary_grouping_size - min_integer_digits}}" : "" integer_regexp = "((#{leading_regexp}#{secondary_groups}#{final_req_digits})|#{final_opt_digits})[0-9]{#{min_integer_digits}}" end end numeric_part_regexp += integer_regexp if max_fraction_digits > 0 if @fractional_grouping_size == 0 fractional_regexp = "" fractional_regexp += "[0-9]{#{min_fraction_digits}}" if min_fraction_digits > 0 fractional_regexp += "[0-9]{0,#{max_fraction_digits - min_fraction_digits}}" unless min_fraction_digits == max_fraction_digits fractional_regexp = "#{Regexp.escape(@decimal_separator)}#{fractional_regexp}" fractional_regexp = "(#{fractional_regexp})?" if min_fraction_digits == 0 numeric_part_regexp += fractional_regexp else fractional_regexp = "" if min_fraction_digits > 0 if min_fraction_digits >= @fractional_grouping_size # first group of required digits - something like "[0-9]{3}" fractional_regexp += "[0-9]{#{@fractional_grouping_size}}" # additional groups of required digits - something like "(,[0-9]{3}){1}" fractional_regexp += "(#{Regexp.escape(@grouping_separator)}[0-9]{#{@fractional_grouping_size}}){#{min_fraction_digits / @fractional_grouping_size - 1}}" if min_fraction_digits / @fractional_grouping_size > 1 fractional_regexp += Regexp.escape(@grouping_separator).to_s if min_fraction_digits % @fractional_grouping_size > 0 end # additional required digits - something like ",[0-9]{1}" fractional_regexp += "[0-9]{#{min_fraction_digits % @fractional_grouping_size}}" if min_fraction_digits % @fractional_grouping_size > 0 opt_fractional_digits = max_fraction_digits - min_fraction_digits if opt_fractional_digits > 0 fractional_regexp += "(" if min_fraction_digits % @fractional_grouping_size > 0 # optional fractional digits to complete the group fractional_regexp += "[0-9]{0,#{[opt_fractional_digits, @fractional_grouping_size - (min_fraction_digits % @fractional_grouping_size)].min}}" fractional_regexp += "|" fractional_regexp += "[0-9]{#{[opt_fractional_digits, @fractional_grouping_size - (min_fraction_digits % @fractional_grouping_size)].min}}" else fractional_regexp += "(#{Regexp.escape(@grouping_separator)}[0-9]{1,#{@fractional_grouping_size}})?" fractional_regexp += "|" fractional_regexp += "#{Regexp.escape(@grouping_separator)}[0-9]{#{@fractional_grouping_size}}" end remaining_opt_fractional_digits = opt_fractional_digits - (@fractional_grouping_size - (min_fraction_digits % @fractional_grouping_size)) if remaining_opt_fractional_digits > 0 if remaining_opt_fractional_digits % @fractional_grouping_size > 0 # optional fraction digits in groups fractional_regexp += "(#{Regexp.escape(@grouping_separator)}[0-9]{#{@fractional_grouping_size}}){0,#{remaining_opt_fractional_digits / @fractional_grouping_size}}" if remaining_opt_fractional_digits > @fractional_grouping_size # remaining optional fraction digits fractional_regexp += "(#{Regexp.escape(@grouping_separator)}[0-9]{1,#{remaining_opt_fractional_digits % @fractional_grouping_size}})?" else # optional fraction digits in groups fractional_regexp += "(#{Regexp.escape(@grouping_separator)}[0-9]{#{@fractional_grouping_size}}){0,#{(remaining_opt_fractional_digits / @fractional_grouping_size) - 1}}" if remaining_opt_fractional_digits > @fractional_grouping_size # remaining optional fraction digits fractional_regexp += "(#{Regexp.escape(@grouping_separator)}[0-9]{1,#{@fractional_grouping_size}})?" end # optional fraction digits in groups fractional_regexp += "(#{Regexp.escape(@grouping_separator)}[0-9]{#{@fractional_grouping_size}}){0,#{(remaining_opt_fractional_digits / @fractional_grouping_size) - 1}}" if remaining_opt_fractional_digits > @fractional_grouping_size # remaining optional fraction digits fractional_regexp += "(#{Regexp.escape(@grouping_separator)}[0-9]{1,#{remaining_opt_fractional_digits % @fractional_grouping_size}})?" if remaining_opt_fractional_digits % @fractional_grouping_size > 0 end fractional_regexp += ")" end elsif max_fraction_digits % @fractional_grouping_size > 0 # optional fractional digits in groups fractional_regexp += "([0-9]{#{@fractional_grouping_size}}#{Regexp.escape(@grouping_separator)}){0,#{max_fraction_digits / @fractional_grouping_size}}" # remaining optional fraction digits fractional_regexp += "(#{Regexp.escape(@grouping_separator)}[0-9]{1,#{max_fraction_digits % @fractional_grouping_size}})?" if max_fraction_digits % @fractional_grouping_size > 0 else fractional_regexp += "([0-9]{#{@fractional_grouping_size}}#{Regexp.escape(@grouping_separator)}){0,#{(max_fraction_digits / @fractional_grouping_size) - 1}}" if max_fraction_digits > @fractional_grouping_size fractional_regexp += "[0-9]{1,#{@fractional_grouping_size}}" end fractional_regexp = "#{Regexp.escape(@decimal_separator)}#{fractional_regexp}" fractional_regexp = "(#{fractional_regexp})?" if min_fraction_digits == 0 numeric_part_regexp += fractional_regexp end end if max_exponent_digits > 0 numeric_part_regexp += "E" numeric_part_regexp += "[0-9]{0,#{max_exponent_digits - min_exponent_digits}}" unless max_exponent_digits == min_exponent_digits numeric_part_regexp += "[0-9]{#{min_exponent_digits}}" unless min_exponent_digits == 0 end @regexp = Regexp.new("^(?<prefix>#{Regexp.escape(@prefix)})(?<numeric_part>#{numeric_part_regexp})(?<suffix>#{suffix})$") end end |
Instance Attribute Details
#decimal_separator ⇒ Object (readonly)
Returns the value of attribute decimal_separator.
4 5 6 |
# File 'lib/csvlint/csvw/number_format.rb', line 4 def decimal_separator @decimal_separator end |
#fractional_grouping_size ⇒ Object (readonly)
Returns the value of attribute fractional_grouping_size.
4 5 6 |
# File 'lib/csvlint/csvw/number_format.rb', line 4 def fractional_grouping_size @fractional_grouping_size end |
#grouping_separator ⇒ Object (readonly)
Returns the value of attribute grouping_separator.
4 5 6 |
# File 'lib/csvlint/csvw/number_format.rb', line 4 def grouping_separator @grouping_separator end |
#integer ⇒ Object (readonly)
Returns the value of attribute integer.
4 5 6 |
# File 'lib/csvlint/csvw/number_format.rb', line 4 def integer @integer end |
#numeric_part ⇒ Object (readonly)
Returns the value of attribute numeric_part.
4 5 6 |
# File 'lib/csvlint/csvw/number_format.rb', line 4 def numeric_part @numeric_part end |
#pattern ⇒ Object (readonly)
Returns the value of attribute pattern.
4 5 6 |
# File 'lib/csvlint/csvw/number_format.rb', line 4 def pattern @pattern end |
#prefix ⇒ Object (readonly)
Returns the value of attribute prefix.
4 5 6 |
# File 'lib/csvlint/csvw/number_format.rb', line 4 def prefix @prefix end |
#primary_grouping_size ⇒ Object (readonly)
Returns the value of attribute primary_grouping_size.
4 5 6 |
# File 'lib/csvlint/csvw/number_format.rb', line 4 def primary_grouping_size @primary_grouping_size end |
#secondary_grouping_size ⇒ Object (readonly)
Returns the value of attribute secondary_grouping_size.
4 5 6 |
# File 'lib/csvlint/csvw/number_format.rb', line 4 def secondary_grouping_size @secondary_grouping_size end |
#suffix ⇒ Object (readonly)
Returns the value of attribute suffix.
4 5 6 |
# File 'lib/csvlint/csvw/number_format.rb', line 4 def suffix @suffix end |
Instance Method Details
#match(value) ⇒ Object
181 182 183 |
# File 'lib/csvlint/csvw/number_format.rb', line 181 def match(value) value&.match?(@regexp) ? true : false end |
#parse(value) ⇒ Object
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/csvlint/csvw/number_format.rb', line 185 def parse(value) if @pattern.nil? return nil if !@grouping_separator.nil? && value =~ Regexp.new("((^#{Regexp.escape(@grouping_separator)})|#{Regexp.escape(@grouping_separator)}{2})") value.gsub!(@grouping_separator, "") unless @grouping_separator.nil? value.gsub!(@decimal_separator, ".") unless @decimal_separator.nil? if value&.match?(@regexp) case value when "NaN" Float::NAN when "INF" Float::INFINITY when "-INF" -Float::INFINITY else case value[-1] when "%" value.to_f / 100 when "‰" value.to_f / 1000 else if @integer.nil? value.include?(".") ? value.to_f : value.to_i else @integer ? value.to_i : value.to_f end end end end else match = @regexp.match(value) return nil if match.nil? number = match["numeric_part"] number.gsub!(@grouping_separator, "") unless @grouping_separator.nil? number.gsub!(@decimal_separator, ".") unless @decimal_separator.nil? number = @integer ? number.to_i : number.to_f number = number.to_f / 100 if match["prefix"].include?("%") || match["suffix"].include?("%") number = number.to_f / 1000 if match["prefix"].include?("‰") || match["suffix"].include?("‰") number end end |