在某些情况下 Roman 到 Int 的转换不正确

Roman to Int converts incorrectly in some cases

我的函数如下所示:

let romanToInt = romanNumber => {
    if(typeof romanNumber !== 'string') throw new TypeError('Argument must be of type String');

    const values = { 'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000 };
    let sum = 0;

    romanNumber.split('').map(n => n.toUpperCase()).forEach(n => sum = (sum >= values[n]) ? sum + values[n] : values[n] - sum);

    return sum;
}

console.log(romanToInt("MCMXCVI"));

我测试的大多数输入都是正确的,但是罗马数字 MCMXCVI 例如应该给我 1996,而不是 2216,这就是我的意思得到。

我找到了这个,但我不确定如何实现它:

You must separate ones, tens, hundreds, and thousands as separate items. That means that 99 is XCIX, 90 + 9, but never should be written as IC. Similarly, 999 cannot be IM and 1999 cannot be MIM.

您不应该希望通过简单的映射来解决问题,因为在罗马数字中,数字的含义取决于上下文。我认为,很多情况都可以用类似的方式处理(而不是你的 split 和 map 行):

var digits = romanNumber.split('');
var i = 0;
while (i < digits.length) {
    if (i == digits.length - 1 || values[digits[i]] >= values[digits[i+1]]) {
        sum += values[digits[i]];
        i++;
    }
    else {
        sum += values[digits[i+1]] - values[digits[i]];
        i += 2;
    }
}

但我不确定它是否适用于所有情况。最好看看它是如何在现成的库中实现的,也许对于其他语言。例如,这里是 Perl 的实现:http://search.cpan.org/~chorny/Roman-1.24/lib/Roman.pm

我认为您不能使用单行映射来实现,因为该操作取决于相邻字符的比较。然而,用一个简单的for循环:

var chars = romanNumber.split('');
var sum = values[chars[chars.length - 1]];
for (var i = chars.length - 2; i >= 0; i--) {
    if (values[chars[i + 1]] <= values[chars[i]]) {
        sum += values[chars[i]];
    } else {
        sum -= values[chars[i]];
    }
}

问题是当一个罗马数字的值小于它右边的数字时,你想从总和中减去它而不是加。

根据你的问题,你需要满足不同的项目。一种简单的方法是简单地使您的值集更大,并寻找多字符匹配项。这是可能的,因为罗马数字只允许几种组合。我把一个fiddle放在一起here

const values = { 
  'I': 1, 
  'V': 5, 
  'X': 10, 
  'L': 50, 
  'C': 100, 
  'D': 500, 
  'M': 1000,
  'CM': 900,
  'CD': 400,
  'XC': 90,
  'XL': 40,
  'IX': 9,
  'IV': 4
};

let sum = 0;

while(romanNumber.length > 0){
  let piece = romanNumber.substring(0,2);
  if(values[piece]){
    sum += values[piece];
    romanNumber = romanNumber.substring(2);
  }else if(values[piece[0]]){
    sum += values[piece[0]];
    romanNumber = romanNumber.substring(1);
  }
}

return sum;