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 conver
This function works for your input value examples.
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 haven't made any effort in testing other inputs than the valid ones you supplied. You may want to e.g. check for Success in at least some of the capture groups, or maybe do validation as a separate step. This code was made with parsing in mind.
Edit:
Here is a more robust 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));
}
It fails for empty strings, and strings with extra characters other than allowed by your examples. Five or more digits are treated as the simpler format.
The changes are the begin- and end anchors and allowed leading and trailing whitespace, as well as the special case check for emtpy/whitespace-only string in the if statement.
Disclaimer: this has obviously not been tested for every possible illegal input, and I am not a c# programmer anyway :-)
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.