Analysis of all possible input types of various architectural sizes

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

Input | Value | Output (Inches represented by double)


12.5' | 12 feet and six inches | 150.0

11" | 11 inches | 11.0

3/16" | 3 sixteenth inch | 0.1875


spaces may or may not be used between the legs and inches and inches and sixteenths.

11' 11" 143.0 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 the legs and inches or between inches and sixteenths or both

12'-11" | 12 feet 155.0 11 inches | 155.0

12' 11 3/16" 155.1875 12' 11 3/16" | 12 feet and 11 inches and 3 sixteenths | 155.1875

12' 11-1/2" 155.5 12' 11-1/2" | 12 feet and 11 inches and 8 sixteenths | 155.5


Any number of spaces can be used between the legs and inches and inches and sixteenths.

12' 11 1/2" 155.5 12' 11 1/2" | 12 feet and 11 inches and 8 sixteenths | 155.5


An alternative simpler format is also available.

121103 | 12 feet and 11 inches and 3 sixteenths | 155.1875


Negative is also possible in each 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 sophisticated set of branching logic to try and determine in what format it is trying to imitate the input ... And this does not work in all cases.

Is there any possible combination of LINQ and regular expressions and witchcraft that we can use to determine how to parse a string?

Also note that we really want to avoid providing a simple combined form in the form to select the type of input format.

+9
string c # regex string-parsing linq
source share
2 answers

This function works for your sample input values.

 public static Double Conv(String inp) { String expr= "((?<feet>\\d+)(?<inch>\\d{2})(?<sixt>\\d{2}))|((?<feet>[\\d.]+)')?[\\s-]*((?<inch>\\d+)?[\\s-]*((?<numer>\\d+)/(?<denom>\\d+))?\")?"; Match m = new Regex(expr).Match(inp); Double feet = m.Groups["feet"].Success ? Convert.ToDouble(m.Groups["feet"].Value) : 0; Int32 inch = m.Groups["inch"].Success ? Convert.ToInt32(m.Groups["inch"].Value) : 0; Int32 sixt = m.Groups["sixt"].Success ? Convert.ToInt32(m.Groups["sixt"].Value) : 0; Int32 numer = m.Groups["numer"].Success ? Convert.ToInt32(m.Groups["numer"].Value) : 0; Int32 denom = m.Groups["denom"].Success ? Convert.ToInt32(m.Groups["denom"].Value) : 1; return feet*12+inch+sixt/16.0+numer/Convert.ToDouble(denom); } 

Please note that I made no effort to test other inputs than the ones you provided. You might want to, for example, check Success, at least in some capture groups, or perhaps do the verification as a separate step. This code was parsed.

Edit:

Here is a more reliable version:

 public static Double Conv(String inp) { String expr= "^\\s*(?<minus>-)?\\s*(((?<feet>\\d+)(?<inch>\\d{2})(?<sixt>\\d{2}))|((?<feet>[\\d.]+)')?[\\s-]*((?<inch>\\d+)?[\\s-]*((?<numer>\\d+)/(?<denom>\\d+))?\")?)\\s*$"; Match m = new Regex(expr).Match(inp); if(!m.Success || inp.Trim()=="") { // maybe throw exception or set/return some failure indicator return 0; // here using return value zero as failure indicator } Int32 sign = m.Groups["minus"].Success ? -1 : 1; Double feet = m.Groups["feet"].Success ? Convert.ToDouble(m.Groups["feet"].Value) : 0; Int32 inch = m.Groups["inch"].Success ? Convert.ToInt32(m.Groups["inch"].Value) : 0; Int32 sixt = m.Groups["sixt"].Success ? Convert.ToInt32(m.Groups["sixt"].Value) : 0; Int32 numer = m.Groups["numer"].Success ? Convert.ToInt32(m.Groups["numer"].Value) : 0; Int32 denom = m.Groups["denom"].Success ? Convert.ToInt32(m.Groups["denom"].Value) : 1; return sign*(feet*12+inch+sixt/16.0+numer/Convert.ToDouble(denom)); } 

Failure for empty lines and lines with extra characters other than your examples. Five or more digits are considered a simpler format.

Changes are leading and trailing anchors and leading and trailing spaces are allowed, as well as special case checking for the line emtpy / whitespace only in the if statement.

Disclaimer: this, obviously, has not been tested for all possible illegal input, and I'm still not a C # programmer :-)

+3
source share

This can lead your complexity from branching logic to regular expression 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 special syntax, and the output is legs * 12 + inch + _sixt_ / 16, using ToDecimal for groups. If not, you will have one or more groups of feet, inches, numbers and denominations if the entry is valid. Use ToDouble for legs and ToDecimal for the rest, and be sure to check the division by zero in the fraction.

Evidence-Based Demo 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)} " } 

exit:

  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 made no effort to test other inputs than the ones you provided. You may want to, for example, check non-zero values, at least in some capture groups, or perhaps perform the test as a separate step. This code was parsed.

+1
source share

All Articles