php 如何在PHP中将罗马数字转换为整数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6265596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 23:50:19  来源:igfitidea点击:

How to convert a Roman numeral to integer in PHP?

phpintegerroman-numerals

提问by kapa

Using PHP, I'd like to convert a string containing a Roman number into its integer representation. I need this because I need to make calculations on them.

使用 PHP,我想将包含罗马数字的字符串转换为其整数表示形式。我需要这个,因为我需要对它们进行计算。

Wikipedia on Roman numerals

关于罗马数字的维基百科

It would suffice to only recognize the basic Roman numeral characters, like:

只识别基本的罗马数字字符就足够了,例如:

$roman_values=array(
    'I' => 1,
    'V' => 5,
    'X' => 10,
    'L' => 50,
    'C' => 100,
    'D' => 500,
    'M' => 1000,
);

That means the highest possible number is 3999 (MMMCMXCIX). I will use Nto represent zero, other than that only positive integers are supported.

这意味着可能的最高数字是 3999 (MMMCMXCIX)。N除了只支持正整数之外,我将用来表示零。

I cannot use the PEAR library for Roman numbers.

我不能将 PEAR 库用于罗马数字。

I found this great question on SO on how to test whether the string contains a valid Roman numeral:

我在 SO 上发现了这个关于如何测试字符串是否包含有效罗马数字的好问题:

How do you match only valid roman numerals with a regular expression?

如何仅将有效的罗马数字与正则表达式匹配?

What would be the best way of coding this?

什么是最好的编码方式?

回答by andyb

How about this:

这个怎么样:

$romans = array(
    '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 = 'MMMCMXCIX';
$result = 0;

foreach ($romans as $key => $value) {
    while (strpos($roman, $key) === 0) {
        $result += $value;
        $roman = substr($roman, strlen($key));
    }
}
echo $result;

which should output 3999 for the supplied $roman. It seems to work for my limited testing:

对于提供的$roman. 它似乎适用于我有限的测试:

MCMXC = 1990
MM = 2000
MMXI = 2011
MCMLXXV = 1975

You might want to do some validation first as well :-)

您可能还想先进行一些验证:-)

回答by akond

I am not sure whether you've got ZF or not, but in case you (or any of you who's reading this) do here is my snippet:

我不确定你是否有 ZF,但如果你(或任何正在阅读本文的人)在这里做,这是我的片段:

$number = new Zend_Measure_Number('MCMLXXV', Zend_Measure_Number::ROMAN);
$number->convertTo (Zend_Measure_Number::DECIMAL);
echo $number->getValue();

回答by kapa

This is the one I came up with, I added the validity check as well.

这是我想出的,我还添加了有效性检查。

class RomanNumber {
    //array of roman values
    public static $roman_values=array(
        'I' => 1, 'V' => 5, 
        'X' => 10, 'L' => 50,
        'C' => 100, 'D' => 500,
        'M' => 1000,
    );
    //values that should evaluate as 0
    public static $roman_zero=array('N', 'nulla');
    //Regex - checking for valid Roman numerals
    public static $roman_regex='/^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/';

    //Roman numeral validation function - is the string a valid Roman Number?
    static function IsRomanNumber($roman) {
         return preg_match(self::$roman_regex, $roman) > 0;
    }

    //Conversion: Roman Numeral to Integer
    static function Roman2Int ($roman) {
        //checking for zero values
        if (in_array($roman, self::$roman_zero)) {
            return 0;
        }
        //validating string
        if (!self::IsRomanNumber($roman)) {
            return false;
        }

        $values=self::$roman_values;
        $result = 0;
        //iterating through characters LTR
        for ($i = 0, $length = strlen($roman); $i < $length; $i++) {
            //getting value of current char
            $value = $values[$roman[$i]];
            //getting value of next char - null if there is no next char
            $nextvalue = !isset($roman[$i + 1]) ? null : $values[$roman[$i + 1]];
            //adding/subtracting value from result based on $nextvalue
            $result += (!is_null($nextvalue) && $nextvalue > $value) ? -$value : $value;
        }
        return $result;
    }
}

回答by binaryLV

Quick idea - go through the Roman number from right to left, if value of $current(more to the left) is smaller than $previous, then subtract it from the result, if larger, then add it.

快速想法 - 从右到左遍历罗马数字,如果$current(向左更多)的值小于$previous,则从结果中减去它,如果较大,则添加它。

$romanValues=array(
    'I' => 1,
    'V' => 5,
    'X' => 10,
    'L' => 50,
    'C' => 100,
    'D' => 500,
    'M' => 1000,
);
$roman = 'MMMCMXCIX';

// RTL
$arabic = 0;
$prev = null;
for ( $n = strlen($roman) - 1; $n >= 0; --$n ) {
    $curr = $roman[$n];
    if ( is_null($prev) ) {
        $arabic += $romanValues[$roman[$n]];
    } else {
        $arabic += $romanValues[$prev] > $romanValues[$curr] ? -$romanValues[$curr] : +$romanValues[$curr];
    }
    $prev = $curr;
}
echo $arabic, "\n";

// LTR
$arabic = 0;
$romanLength = strlen($roman);
for ( $n = 0; $n < $romanLength; ++$n ) {
    if ( $n === $romanLength - 1 ) {
        $arabic += $romanValues[$roman[$n]];
    } else {
        $arabic += $romanValues[$roman[$n]] < $romanValues[$roman[$n+1]] ? -$romanValues[$roman[$n]] : +$romanValues[$roman[$n]];
    }
}
echo $arabic, "\n";

Some validation of roman number should also be added, though you said that you already have found how to do it.

还应该添加一些对罗马数字的验证,尽管您说您已经找到了方法。

回答by publikz.com

Copyrights is for this blog (btw!) http://scriptsense.blogspot.com/2010/03/php-function-number-to-roman-and-roman.html

版权属于这个博客(顺便说一句!) http://scriptsense.blogspot.com/2010/03/php-function-number-to-roman-and-roman.html

<?php

function roman2number($roman){
    $conv = array(
        array("letter" => 'I', "number" => 1),
        array("letter" => 'V', "number" => 5),
        array("letter" => 'X', "number" => 10),
        array("letter" => 'L', "number" => 50),
        array("letter" => 'C', "number" => 100),
        array("letter" => 'D', "number" => 500),
        array("letter" => 'M', "number" => 1000),
        array("letter" => 0, "number" => 0)
    );
    $arabic = 0;
    $state = 0;
    $sidx = 0;
    $len = strlen($roman);

    while ($len >= 0) {
        $i = 0;
        $sidx = $len;

        while ($conv[$i]['number'] > 0) {
            if (strtoupper(@$roman[$sidx]) == $conv[$i]['letter']) {
                if ($state > $conv[$i]['number']) {
                    $arabic -= $conv[$i]['number'];
                } else {
                    $arabic += $conv[$i]['number'];
                    $state = $conv[$i]['number'];
                }
            }
            $i++;
        }

        $len--;
    }

    return($arabic);
}


function number2roman($num,$isUpper=true) {
    $n = intval($num);
    $res = '';

    /*** roman_numerals array ***/
    $roman_numerals = array(
        '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
    );

    foreach ($roman_numerals as $roman => $number)
    {
        /*** divide to get matches ***/
        $matches = intval($n / $number);

        /*** assign the roman char * $matches ***/
        $res .= str_repeat($roman, $matches);

        /*** substract from the number ***/
        $n = $n % $number;
    }

    /*** return the res ***/
    if($isUpper) return $res;
    else return strtolower($res);
}

/* TEST */
echo $s=number2roman(1965,true);
echo "\n and bacK:\n";
echo roman2number($s);


?>

回答by akTed

I'm late to the party, but here's mine. Assumes valid Numerals in the string, but doesn't test for a valid Roman number, whatever that is...there doesn't seem to be a consensus. This function will work for Roman numbers like VC(95), or MIM(1999), or MMMMMM(6000).

我参加聚会迟到了,但这是我的。假设字符串中的数字有效,但不测试有效的罗马数字,无论是什么......似乎没有达成共识。此函数适用于罗马数字,如VC(95)、MIM(1999) 或MMMMMM(6000)。

function roman2dec( $roman ) {
    $numbers = array(
        'I' => 1,
        'V' => 5,
        'X' => 10,
        'L' => 50,
        'C' => 100,
        'D' => 500,
        'M' => 1000,
    );

    $roman = strtoupper( $roman );
    $length = strlen( $roman );
    $counter = 0;
    $dec = 0;
    while ( $counter < $length ) {
        if ( ( $counter + 1 < $length ) && ( $numbers[$roman[$counter]] < $numbers[$roman[$counter + 1]] ) ) {
            $dec += $numbers[$roman[$counter + 1]] - $numbers[$roman[$counter]];
            $counter += 2;
        } else {
            $dec += $numbers[$roman[$counter]];
            $counter++;
        }
    }
    return $dec;
}

回答by Daniel

Just stumbled across this beauty and have to post it all over:

刚刚偶然发现了这个美女,不得不把它全部贴出来:

function roman($N)
{
    $c = 'IVXLCDM';
    for ($a = 5, $b = $s = ''; $N; $b++, $a ^= 7)
    {
        for (
            $o = $N % $a, $N = $N / $a ^ 0;

            $o--;

            $s = $c[$o > 2 ? $b + $N - ($N &= -2) + $o = 1 : $b] . $s
        );
    }
    return $s;
}

回答by scheruku

function Romannumeraltonumber($input_roman){
  $di=array('I'=>1,
            'V'=>5,
            'X'=>10,
            'L'=>50,
            'C'=>100,
            'D'=>500,
            'M'=>1000);
  $result=0;
  if($input_roman=='') return $result;
  //LTR
  for($i=0;$i<strlen($input_roman);$i++){ 
    $result=(($i+1)<strlen($input_roman) and 
          $di[$input_roman[$i]]<$di[$input_roman[$i+1]])?($result-$di[$input_roman[$i]]) 
                                                        :($result+$di[$input_roman[$i]]);
   }
 return $result;
}

回答by Dariusz Majchrzak

function rom_to_arabic($number) {

$symbols = array( 
    'M'  => 1000,  
    'D'  => 500, 
    'C'  => 100, 
    'L'  => 50, 
    'X'  => 10, 
    'V'  => 5, 
    'I'  => 1);

$a = str_split($number);

$i = 0;
$temp = 0;
$value = 0;
$q = count($a);
while($i < $q) {

    $thys = $symbols[$a[$i]];
    if(isset($a[$i +1])) {
        $next = $symbols[$a[$i +1]];
    } else {
        $next = 0;
    }

    if($thys < $next) {
        $value -= $thys;
    } else {
        $value += $thys;
    }

    $temp = $thys;
    $i++;
}

return $value;

}

回答by Manojkiran.A

try this simple function

试试这个简单的功能

function arabicToRomanNumber($arabicNumber='') {

            $arabicNumValue = intval($arabicNumber);
            $convertedNumber = '';
            $romans = array(
                '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);
            foreach ($romans as $roman => $romanValue) 
            {
                  $matchingNumber = intval($arabicNumValue / $romanValue); // Determine the number of matches
                  $convertedNumber .= str_repeat($roman, $matchingNumber); // Store that many characters
                  $arabicNumValue = $arabicNumValue % $romanValue; // Substract that from the number
            }

            return $convertedNumber;

      }

and finall just pass the arabic numbers as

最后只传递阿拉伯数字作为

echo arabicToRomanNumber('25');//result will be XXV

echo arabicToRomanNumber('25');//结果将是 XXV

echo arabicToRomanNumber('250');//result will be CCL

echo arabicToRomanNumber('250');//结果将是 CCL