Parses string with roman numerals.
Pass the string in any case as argument.
This version parses and “non-well-formed” roman numerals (like IIIII or MIM) as well.
| function( | |
| a // string | |
| /* I just like when function's length property return something meaningful */ | |
| ){ | |
| // Processing each char of `a` starting from the end of string: | |
| for( | |
| // Define the variables: | |
| // v - value. To be assigned later | |
| // s - sum | |
| // i - iterator, length of the arg | |
| var v, s = 0, i = a.length | |
| ; | |
| // decrease iterator with post-decrement | |
| i-- | |
| ; | |
| // add the following to sum: | |
| s += | |
| // stored is more than following expression... | |
| v > ( | |
| // ...where current value is re-assigned. | |
| // Here we define an array using elision | |
| // and right after that get its value on key that is an integer: | |
| v = [100,500,,,,,1,,,50,1e3,,,,,,,,,5,,10][ | |
| // Get the char at the `i` offset and treat it as it was an integer in 36-based notation. | |
| // The good thing: we don't need to use lo-ong toUpperCase :) | |
| // And then decrease it by 12. This makes the array declaration slightly shorter | |
| parseInt(a.charAt(i), 36) - 12 | |
| ] | |
| // Here we get a positive value if char was one of: "IVXLCDMivxlcdm" and undefined else | |
| // Using the subtraction check if this value is less than previous | |
| // (Considering the fact we're parsing string from the tail, this is not the previous but *next* char) | |
| // If there was no previous value, the whole subtraction gives NaN and comparation gives false | |
| ) ? | |
| // If yes (i.e. IX or CM) we should subtract the current value from the sum | |
| -v | |
| : | |
| // If no (i.e. XX or L{end-of-string}) we should add the current value to the sum | |
| // If `v` is a NaN here, the sum will be NaN either. Garbage In Garbage Out, hehe. | |
| // Uncomment ~~ if you don't like this behavior, there's still bytes left. | |
| /* ~~ */ v | |
| ) | |
| /* empty loop body */ | |
| ; | |
| // return the sum | |
| return s | |
| } |
| function(a){for(var v,s=0,i=a.length;i--;s+=v>(v=[100,500,,,,,1,,,50,1e3,,,,,,,,,5,,10][parseInt(a.charAt(i),36)-12])?-v:v);return s} |
| DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
| Version 2, December 2004 | |
| Copyright (C) 2011 subzey <[email protected]> | |
| Everyone is permitted to copy and distribute verbatim or modified | |
| copies of this license document, and changing it is allowed as long | |
| as the name is changed. | |
| DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
| TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
| 0. You just DO WHAT THE FUCK YOU WANT TO. |
| { | |
| "name": "parseRoman", | |
| "description": "Parses roman numerals", | |
| "keywords": [ | |
| "roman", | |
| "numeral", | |
| "parse" | |
| ] | |
| } |
| <!DOCTYPE html> | |
| <title>parseRoman</title> | |
| <div>Expected value: <b>1986,1999,NaN</b></div> | |
| <div>Actual value: <b id="ret"></b></div> | |
| <script> | |
| // write a small example that shows off the API for your example | |
| // and tests it in one fell swoop. | |
| var myFunction = function(a){for(var v,s=0,i=a.length;i--;s+=v>(v=[100,500,,,,,1,,,50,1e3,,,,,,,,,5,,10][parseInt(a.charAt(i),36)-12])?-v:v);return s} | |
| document.getElementById( "ret" ).innerHTML = [myFunction("mcmlxxxvi"), myFunction("MIM"), myFunction("foobarbaz")] | |
| </script> |
| /* | |
| Alternative version | |
| --- | |
| Use this only when string consists *only* from chars: | |
| I, V, X, L, C, D, M, | |
| i, v, x, l, c, d, m | |
| Anything other will return complete trash | |
| */ | |
| function(a){for(var v,s=0,i=a.length;i--;s+=v-(v=[1e3,,5,1,10,100,500,50][1.1*parseInt(a.charAt(i),36)&7])>0?-v:v);return s} |
If you don't care for IE compatibility (or tell IE users to .split('') the input string before using the function), you can replace .charAt() with [], too.
Maybe save 2 bytes?
function(a){for(var v,s=0,i=a.length;i--;s+=v>(v=[100,500,,,,,1,,,50,1e3,,,,,,,,,5,,10][parseInt(a.charAt(i),36)-12])?-v:v);return s}
@tsaniel, very nice suggestion, thanks! I'll update the code.
Made it smaller:
function(a,v,s){for(s=0,i=a.length;i--;s+=v>(v=[100,500,,,,,1,,,50,1e3,,,,,,,,,5,,10][parseInt(a[i],36)-12])?-v:v);return s}
@williammalo, thanks!
I'd rather avoid using string numeric keys due to old IE, while var → argumets is a great advice
@williammalo Oh... In your version i leaks into outer scope
@subzey
Oh noes!
I think that way, too. I just tried to “strip” some of those commas anyhow.