Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing all possible types of varying architectural dimension input

I am writing a library for our company's product that will take any kind of architectural dimension that our users are already familiar with as input for a function that converts from a string to a double. Here is the list of input types that we would like to be valid.

Input| Meaning | Output(Inches represented by a double)


12.5' | 12 Feet and six inches | 150.0

11" | 11 Inches | 11.0

3/16" | 3 sixteenths of an Inch | 0.1875


spaces may or may not be used between the feet and inches and the inches and sixteenths

11' 11" | 11 Feet and 11 Inches | 143.0

11'11" | 11 Feet and 11 Inches | 143.0


Dashes may or may not be used between feet and inches or between inches and sixteenths or both

12'-11" | 12 Feet and 11 Inches | 155.0

12' 11 3/16" | 12 Feet and 11 Inches and 3 sixteenths | 155.1875

12' 11-1/2" | 12 Feet and 11 Inches and 8 sixteenths | 155.5


Any number of spaces may be used between the feet and inches and the inches and sixteenths

12' 11 1/2" | 12 Feet and 11 Inches and 8 sixteenths | 155.5


An alternate simpler format is also available

121103 | 12 Feet and 11 Inches and 3 sixteenths | 155.1875


Negatives are also possible in every format

-121103 | 12 Feet and 11 Inches and 3 sixteenths | -155.1875

-11'11" | 11 Feet and 11 Inches | -143.0

We are currently using an extremely complicated set of branching logic to try and determine what format the input is trying to emulate... And it doesn't work in all cases.

Is there some possible combination of LINQ and Regular Expressions and witchcraft that we can use to determine how to parse the string?

Also note that we really want to avoid giving a simple combobox on the form to select the input format type from.

like image 347
jth41 Avatar asked Apr 01 '14 18:04

jth41


1 Answers

This may move your complexity from the branching logic to the regex logic:

/(?<special>(?<feet>\d+)(?<inch>\d{2})(?<sixt>\d{2}))|((?<feet>[\d.]+)')?[\s-]*((?<inch>\d+)?[\s-]*((?<numer>\d+)\/(?<denom>\d+))?")?/

If group special matches, you have the special syntax, and output is feet*12+inch+_sixt_/16, using ToDecimal on the groups. If not, you will have one or more of the groups feet, inch, numer and denom if the input is valid. Use ToDouble for feet and ToDecimal for the rest, and make sure to check for division by zero in the fraction.

Proof-of-concept demonstration code (ruby):

[
  ["12.5' "," 12 Feet and six inches "," 150.0"],
  ["11\"  "," 11 Inches "," 11.0"],
  ["3/16\" "," 3 sixteenths of an Inch "," 0.1875"],
  ["11' 11\" "," 11 Feet and 11 Inches "," 143.0"],
  ["11'11\" "," 11 Feet and 11 Inches "," 143.0"],
  ["12'-11\" "," 12 Feet and 11 Inches "," 155.0"],
  ["12' 11 3/16\" "," 12 Feet and 11 Inches and 3 sixteenths "," 155.1875"],
  ["12' 11-1/2\" "," 12 Feet and 11 Inches and 8 sixteenths "," 155.5"],
  ["12'   11     1/2\" "," 12 Feet and 11 Inches and 8 sixteenths "," 155.5"],
  ["121103 "," 12 Feet and 11 Inches and 3 sixteenths "," 155.1875"],
  ["", "empty string", "0"],
].each{|i,d,o|
  m = /(?<special>(?<feet>\d+)(?<inch>\d{2})(?<sixt>\d{2}))|((?<feet>[\d.]+)')?[\s-]*((?<inch>\d+)?[\s-]*((?<numer>\d+)\/(?<denom>\d+))?")?/.match(i)
  #puts "#{(1..8).map{|n|"%15s"%m[n].inspect}.join}"
  puts "#{"%20s"%i}   #{"%10s"%o}   #{m[:special] ? m[:feet].to_i*12+m[:inch].to_i+m[:sixt].to_i/16.0 : m[:feet].to_f*12+m[:inch].to_i+(m[:numer].to_i.to_f/(m[:denom]||1).to_i)} "
}

output:

              12.5'         150.0   150.0 
               11"           11.0   11.0 
              3/16"        0.1875   0.1875 
            11' 11"         143.0   143.0 
             11'11"         143.0   143.0 
            12'-11"         155.0   155.0 
       12' 11 3/16"      155.1875   155.1875 
        12' 11-1/2"         155.5   155.5 
  12'   11     1/2"         155.5   155.5 
             121103      155.1875   155.1875 
                                0   0.0 

Please note that I haven't made any effort in testing other inputs than the valid ones you supplied. You may want to e.g. check for non-nil values in at least some of the capture groups, or maybe do validation as a separate step. This code was made with parsing in mind.

like image 188
Trygve Flathen Avatar answered Nov 15 '22 06:11

Trygve Flathen