Skip to content

Instantly share code, notes, and snippets.

@subzey
Forked from 140bytes/LICENSE.txt
Created Jun 22, 2011
Embed
What would you like to do?
parseRoman

parseRoman

Parses string with roman numerals.

Usage

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 <subzey@immelman.ru>
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}
@atk
Copy link

atk commented Jun 22, 2011

What a great idea to use base36 integer parsing to convert the characters to something parseable and ignore the case at the same time! I guess you could save another byte by using %14 instead of -12:

v={4:1,3:5,5:10,7:50,12:100,13:500,8:1e3}[parseInt(a.charAt(i),36)%14] // does the same as
v={6:1,19:5,21:10,9:50,0:100,1:500,10:1e3}[parseInt(a.charAt(i),36)-12]

@subzey
Copy link
Author

subzey commented Jun 22, 2011

@atk, thank you! I will update the code in a moment.

@subzey
Copy link
Author

subzey commented Jun 22, 2011

@atk, thanks to your suggestion I could use array instead of object and the code is 11 bytes shorter. That's a really great advice!

@atk
Copy link

atk commented Jun 22, 2011

You're welcome! And that's another really cool idea! Btw, you forgot to update test.html.

@subzey
Copy link
Author

subzey commented Jun 22, 2011

Oh, noes! That breaks the validation so using "8C8LJJJVI" yields same as "MCMLXXXVI".
Guess, I should revert to the previous version as I already have x-alternative.js in this gist that doesn't validate its input.

@atk
Copy link

atk commented Jun 22, 2011

Completely forgot about the validation... anyway,

[100,500,,,,,1,,,50,1e3,,,,,,,,,5,,10] is still 2 bytes shorter than {6:1,19:5,21:10,9:50,0:100,1:500,10:1e3}

@subzey
Copy link
Author

subzey commented Jun 24, 2011

I think that way, too. I just tried to “strip” some of those commas anyhow.

@atk
Copy link

atk commented Jun 25, 2011

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.

@tsaniel
Copy link

tsaniel commented Oct 8, 2011

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}

@subzey
Copy link
Author

subzey commented Oct 8, 2011

@tsaniel, very nice suggestion, thanks! I'll update the code.

@williammalo
Copy link

williammalo commented Apr 11, 2012

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}

@subzey
Copy link
Author

subzey commented Apr 12, 2012

@williammalo, thanks!

I'd rather avoid using string numeric keys due to old IE, while var → argumets is a great advice

@subzey
Copy link
Author

subzey commented Apr 12, 2012

@williammalo Oh... In your version i leaks into outer scope

@williammalo
Copy link

williammalo commented Apr 12, 2012

@subzey
Oh noes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment