Преобразовать число в римскую цифру в javaScript - PullRequest
50 голосов
/ 31 января 2012

Как я могу преобразовать целые числа в римские цифры ?

function romanNumeralGenerator (int) {

}

Например, см. Следующие примеры входов и выходов:

1 = "I"
5 = "V"
10 = "X"
20 = "XX"
3999 = "MMMCMXCIX"

Предупреждение: поддерживаются только цифры от 1 до 3999

Ответы [ 58 ]

81 голосов
/ 31 января 2012

В этом блоге есть один замечательный пример, который я нашел с помощью Google:

http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter

function romanize (num) {
    if (isNaN(num))
        return NaN;
    var digits = String(+num).split(""),
        key = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM",
               "","X","XX","XXX","XL","L","LX","LXX","LXXX","XC",
               "","I","II","III","IV","V","VI","VII","VIII","IX"],
        roman = "",
        i = 3;
    while (i--)
        roman = (key[+digits.pop() + (i * 10)] || "") + roman;
    return Array(+digits.join("") + 1).join("M") + roman;
}
62 голосов
/ 29 сентября 2015
function romanize(num) {
  var lookup = {M:1000,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1},roman = '',i;
  for ( i in lookup ) {
    while ( num >= lookup[i] ) {
      roman += i;
      num -= lookup[i];
    }
  }
  return roman;
}

Перемещено из комментария 2008 года, расположенного по адресу: http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter

ПОСМОТРЕТЬ ДЕМО

39 голосов
/ 28 декабря 2016

Я не понимаю, почему решение anyones такое длинное и использует несколько циклов for.

function convertToRoman(num) {
  var roman = {
    M: 1000,
    CM: 900,
    D: 500,
    CD: 400,
    C: 100,
    XC: 90,
    L: 50,
    XL: 40,
    X: 10,
    IX: 9,
    V: 5,
    IV: 4,
    I: 1
  };
  var str = '';

  for (var i of Object.keys(roman)) {
    var q = Math.floor(num / roman[i]);
    num -= q * roman[i];
    str += i.repeat(q);
  }

  return str;
}
13 голосов
/ 31 января 2012

Эти функции преобразуют любое положительное целое число в его эквивалентную строку римской цифры; и любой римский номер на его номер.

Номер римской цифрой:

Number.prototype.toRoman= function () {
    var num = Math.floor(this), 
        val, s= '', i= 0, 
        v = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1], 
        r = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I']; 

    function toBigRoman(n) {
        var ret = '', n1 = '', rem = n;
        while (rem > 1000) {
            var prefix = '', suffix = '', n = rem, s = '' + rem, magnitude = 1;
            while (n > 1000) {
                n /= 1000;
                magnitude *= 1000;
                prefix += '(';
                suffix += ')';
            }
            n1 = Math.floor(n);
            rem = s - (n1 * magnitude);
            ret += prefix + n1.toRoman() + suffix;
        }
        return ret + rem.toRoman();
    }

    if (this - num || num < 1) num = 0;
    if (num > 3999) return toBigRoman(num);

    while (num) {
        val = v[i];
        while (num >= val) {
            num -= val;
            s += r[i];
        }
        ++i;
    }
    return s;
};

Строка из римских цифр в число:

Number.fromRoman = function (roman, accept) {
    var s = roman.toUpperCase().replace(/ +/g, ''), 
        L = s.length, sum = 0, i = 0, next, val, 
        R = { M: 1000, D: 500, C: 100, L: 50, X: 10, V: 5, I: 1 };

    function fromBigRoman(rn) {
        var n = 0, x, n1, S, rx =/(\(*)([MDCLXVI]+)/g;

        while ((S = rx.exec(rn)) != null) {
            x = S[1].length;
            n1 = Number.fromRoman(S[2])
            if (isNaN(n1)) return NaN;
            if (x) n1 *= Math.pow(1000, x);
            n += n1;
        }
        return n;
    }

    if (/^[MDCLXVI)(]+$/.test(s)) {
        if (s.indexOf('(') == 0) return fromBigRoman(s);

        while (i < L) {
            val = R[s.charAt(i++)];
            next = R[s.charAt(i)] || 0;
            if (next - val > 0) val *= -1;
            sum += val;
        }
        if (accept || sum.toRoman() === s) return sum;
    }
    return NaN;
};
13 голосов
/ 09 июня 2016

Я разработал рекурсивное решение ниже. Функция возвращает одну букву, а затем вызывает себя, чтобы вернуть следующую букву. Это происходит до тех пор, пока число, переданное функции, не станет 0, что означает, что все буквы были найдены, и мы можем выйти из рекурсии.

var romanMatrix = [
  [1000, 'M'],
  [900, 'CM'],
  [500, 'D'],
  [400, 'CD'],
  [100, 'C'],
  [90, 'XC'],
  [50, 'L'],
  [40, 'XL'],
  [10, 'X'],
  [9, 'IX'],
  [5, 'V'],
  [4, 'IV'],
  [1, 'I']
];

function convertToRoman(num) {
  if (num === 0) {
    return '';
  }
  for (var i = 0; i < romanMatrix.length; i++) {
    if (num >= romanMatrix[i][0]) {
      return romanMatrix[i][1] + convertToRoman(num - romanMatrix[i][0]);
    }
  }
}
8 голосов
/ 22 августа 2015

Я знаю, что это старый вопрос, но я очень горжусь этим решением :) Оно обрабатывает только числа меньше 1000, но может быть легко расширено, чтобы включить в него столько, сколько вам нужно, добавив 2D «NumberralCodes» 2D массив.

var numeralCodes = [["","I","II","III","IV","V","VI","VII","VIII","IX"],         // Ones
                    ["","X","XX","XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"],   // Tens
                    ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"]];        // Hundreds

function convert(num) {
  var numeral = "";
  var digits = num.toString().split('').reverse();
  for (var i=0; i < digits.length; i++){
    numeral = numeralCodes[i][parseInt(digits[i])] + numeral;
  }
  return numeral;  
}
<input id="text-input" type="text">
<button id="convert-button" onClick="var n = parseInt(document.getElementById('text-input').value);document.getElementById('text-output').value = convert(n);">Convert!</button>
<input id="text-output" style="display:block" type="text">
5 голосов
/ 31 января 2012

JavaScript

function romanize (num) {
    if (!+num)
        return false;
    var digits = String(+num).split(""),
        key = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM",
               "","X","XX","XXX","XL","L","LX","LXX","LXXX","XC",
               "","I","II","III","IV","V","VI","VII","VIII","IX"],
        roman = "",
        i = 3;
    while (i--)
        roman = (key[+digits.pop() + (i * 10)] || "") + roman;
    return Array(+digits.join("") + 1).join("M") + roman;
}

многие другие предложения можно найти на http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter

4 голосов
/ 02 июля 2015

Лично я считаю, что самый лучший способ (ни в коем случае не самый быстрый) - это рекурсия.

function convert(num) { 
  if(num < 1){ return "";}
  if(num >= 40){ return "XL" + convert(num - 40);}
  if(num >= 10){ return "X" + convert(num - 10);}
  if(num >= 9){ return "IX" + convert(num - 9);}
  if(num >= 5){ return "V" + convert(num - 5);}
  if(num >= 4){ return "IV" + convert(num - 4);}
  if(num >= 1){ return "I" + convert(num - 1);}  
}
console.log(convert(39)); 
//Output: XXXIX

Это будет поддерживать только числа 1-40 , но его можно легко расширить, следуя шаблону.

3 голосов
/ 21 июня 2016

После тестирования некоторых реализаций в этом посте я создал новую оптимизированную для более быстрого выполнения.Время выполнения действительно мало по сравнению с другими, но, очевидно, код выглядит ужаснее :).Это может быть даже быстрее с индексированным массивом со всеми возможностями.На всякий случай это кому-нибудь поможет.

function concatNumLetters(letter, num) {
    var text = "";
    for(var i=0; i<num; i++){
        text += letter;
    }
    return text;
}


function arabicToRomanNumber(arabic) {
    arabic = parseInt(arabic);
    var roman = "";
    if (arabic >= 1000) {
        var thousands = ~~(arabic / 1000);
        roman = concatNumLetters("M", thousands);
        arabic -= thousands * 1000;
    }

     if (arabic >= 900) {
         roman += "CM";
         arabic -= 900;
     }

     if (arabic >= 500) {
         roman += "D";
         arabic -= 500;
     }

     if (arabic >= 400) {
         roman += "CD";
         arabic -= 400;
     }

     if (arabic >= 100) { 
        var hundreds = ~~(arabic / 100);
        roman += concatNumLetters("C", hundreds);
        arabic -= hundreds * 100;
     }

     if (arabic >= 90) {
         roman += "XC";
         arabic -= 90;
     }

     if (arabic >= 50) {
         roman += "L";
         arabic -= 50;
     }

     if (arabic >= 40) {
         roman += "XL";
         arabic -= 40;
     }

     if (arabic >= 10) {
        var dozens = ~~(arabic / 10);
        roman += concatNumLetters("X", dozens);
        arabic -= dozens * 10;
     }

     if (arabic >= 9) {
         roman += "IX";
         arabic -= 9;
     }

      if (arabic >= 5) {
         roman += "V";
         arabic -= 5;
     }

     if (arabic >= 4) {
         roman += "IV";
         arabic -= 4;
     }

     if (arabic >= 1) {
        roman += concatNumLetters("I", arabic);
     }

     return roman;
}
3 голосов
/ 19 ноября 2018
function convertToRoman(num) {
  var roman = {
    M: 1000,
    CM: 900,
    D: 500,
    CD: 400,
    C: 100,
    XC: 90,
    L: 50,
    XL: 40,
    X: 10,
    IX: 9,
    V: 5,
    IV: 4,
    I: 1
  }
  var result = '';
  for (var key in roman) {
    if (num == roman[key]) {
      return result +=key;
    }
    var check = num > roman[key];
    if(check) {
      result = result + key.repeat(parseInt(num/roman[key]));
      num = num%roman[key];
    }
  }
 return result;
}

console.log(convertToRoman(36));
...