python-3.x 检查输入是否为有效的罗马数字

omjgkv6w  于 2023-11-20  发布在  Python
关注(0)|答案(7)|浏览(101)

我有一个程序,可以将罗马数字转换为整数,反之亦然。我的问题是,我真的不知道如何创建一个函数来检查用户输入是否是有效的罗马数字。我现在的代码:

def checkIfRomanNumeral(numeral):
"""Controls that the userinput only contains valid roman numerals"""
    numeral = numeral.upper()
    validRomanNumerals = ["M", "D", "C", "L", "X", "V", "I", "(", ")"]
    for letters in numeral:
        if letters not in validRomanNumerals:
            print("Sorry that is not a valid roman numeral")
            return True
        elif letters in validRomanNumerals:
            romanToInt(numeral)
            break

字符串
我认为现在的问题是,由于for循环的原因,该函数只检查输入(numeric)中的第一个字母。有人能帮助我让函数检查整个输入并打印(“对不起,这不是一个有效的罗马数字”),如果输入的任何字母不是罗马数字。validRomanNumerals列表中的括号用于转换大于4000的数字,所以它们必须在那里。

8ehkhllq

8ehkhllq1#

编写从int到Romans的转换器是一个标准的面试问题。我曾经写过以下双向实现(toString--十进制到罗马; parse--罗马到十进制)。该实现满足了罗马数表示的一些额外标准,这些标准不是强制性的,但通常遵循:

'''
Created on Feb 7, 2013

@author: olegs
'''

ROMAN_CONSTANTS = (
            ( "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" ),
            ( "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" ),
            ( "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" ),
            ( "", "M", "MM", "MMM", "",   "",  "-",  "",    "",     ""   ),
        )

ROMAN_SYMBOL_MAP = dict(I=1, V=5, X=10, L=50, C=100, D=500, M=1000)

CUTOFF = 4000
BIG_DEC = 2900
BIG_ROMAN = "MMCM"
ROMAN_NOUGHT = "nulla"

def digits(num):
    if num < 0:
        raise Exception('range error: negative numbers not supported')
    if num % 1 != 0.0:
        raise Exception('floating point numbers not supported')
    res = []
    while num > 0:
        res.append(num % 10)
        num //= 10
    return res

def toString(num, emptyZero=False):
    if num < CUTOFF:
        digitlist = digits(num)
        if digitlist:
            res = reversed([ ROMAN_CONSTANTS[order][digit] for order, digit in enumerate(digitlist) ])
            return "".join(res)
        else:
            return "" if emptyZero else ROMAN_NOUGHT 
    else:
        if num % 1 != 0.0:
            raise Exception('floating point numbers not supported')
        # For numbers over or equal the CUTOFF, the remainder of division by 2900
        # is represented as above, prepended with the multiples of MMCM (2900 in Roman),
        # which guarantees no more than 3 repetitive Ms.
        return BIG_ROMAN * (num // BIG_DEC) + toString(num % BIG_DEC, emptyZero=True)

def parse(numeral):
    numeral = numeral.upper()
    result = 0
    if numeral == ROMAN_NOUGHT.upper():
        return result
    lastVal = 0
    lastCount = 0
    subtraction = False
    for symbol in numeral[::-1]:
        value = ROMAN_SYMBOL_MAP.get(symbol)
        if not value:
            raise Exception('incorrect symbol')
        if lastVal == 0:
            lastCount = 1
            lastVal = value
        elif lastVal == value:
            lastCount += 1
            # exceptions
        else:
            result += (-1 if subtraction else 1) * lastVal * lastCount
            subtraction = lastVal > value
            lastCount = 1
            lastVal = value
    return result + (-1 if subtraction else 1) * lastVal * lastCount

字符串

0x6upsns

0x6upsns2#

def checkIfRomanNumeral(numeral):
"""Controls that the userinput only contains valid roman numerals"""
    numeral = numeral.upper()
    validRomanNumerals = ["M", "D", "C", "L", "X", "V", "I", "(", ")"]
    valid = True
    for letters in numeral:
        if letters not in validRomanNumerals:
            print("Sorry that is not a valid roman numeral")
            valid = False
            break
    return valid

字符串
返回一个布尔值,无论给定的“numeric "是否是罗马数字。

kjthegm6

kjthegm63#

除了已经指出的设计问题,我想回答这个问题为什么你的for循环没有遍历所有的数字
如果你的代码认为这些条目是有效的,那么循环进入elif子句,在那里它调用romanToInt(numeral),然后调用break
说明:只要满足本例中的条件,循环将停止通过i in list

for i in list:
   # do something
   if condition:
       break # "Stop the innermost loop now!"

字符串

irtuqstp

irtuqstp4#

代替循环,你可以将输入和有效的文字都转换成集合,然后对它们进行子操作:

def checkIfRomanNumeral(numeral):
    numeral = {c for c in numeral.upper()}
    validRomanNumerals = {c for c in "MDCLXVI()"}
    return not numeral - validRomanNumerals

字符串
如果numeral有效,则返回True,否则返回False。(假设空字符串有效)

t30tvxxf

t30tvxxf5#

有一种方法我建立的解决方案,你可以很容易地修改它,以您的需要,甚至得到的数字。我的程序是打印,如果从用户的字符串是一个有效的数字,但你可以很容易地改变它,以获得实际的值。

def main():
    # YOUR CODE GOES HERE
    # Please take input and print output to standard input/output (stdin/stdout)
    # E.g. 'input()/raw_input()' for input & 'print' for output
    N = 1
    for i in range(N):
        romanStr = input() # your str
        units = ["I", "II", "III" , 'IV' , 'V', 'VI', 'VII', 'VIII', "IX"]
        tens = ['X', "XX", "XXX", 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC']
        hundreds = ['C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM']
        thousands = ['M', 'MM', 'MMM']
        allTypes = [units, tens, hundreds, thousands][::-1]
        isError = False
        lenRom = len(romanStr)
        copy = romanStr
        while len(copy) > 0 and len(allTypes) > 0:
            currentUnit = allTypes[0]
            # check units
            firstNum = copy[0]
            lastTwo = copy[:2]
            last3 = copy[:3]
            last4 = copy[:4]
            isLastTwo = lastTwo in currentUnit and len(lastTwo) == 2
            isLast3 = last3 in currentUnit and len(last3) == 3
            isLast4 = last4 in currentUnit and len(last4) == 4
            
            if (firstNum in currentUnit and not (isLastTwo or isLast3 or isLast4) ):
                copy = copy[1::]
                isError = False
            elif (isLastTwo and not (isLast3 or isLast4) ):
                copy = copy[2::]
                isError = False
            elif (isLast3 and not (isLast4) ):
                copy = copy[3::]
                isError = False
            elif (isLast4):
                copy = copy[4::]
                isError = False
            else:
                
                isError = True
                # copy = ''
            allTypes.pop(0)
        
        if (isError or len(copy) != 0 ):
            print("NO")
            return 0
        else:
            print("YES")
            return 1

    return 0

if __name__ == '__main__':
    main()

字符串

e37o9pze

e37o9pze6#

我知道最初的海报是用Python写的,但我已经从上面引用了Oleg的答案,将其移植到PHP,并纠正了它的缺陷。
这段PHP代码应该正确地将罗马数字转换为数字,并且不应该允许转换无效的罗马数字。

<?php
define('ROMAN_VERBOSE', true);

class RomanNumeral {

protected static $lookup2 = [
   'I' => 1,
   'V' => 5,
   'X' => 10,
   'L' => 50,
   'C' => 100,
   'D' => 500,
   'M' => 1000,
];

public static function toNumber($numeral) {
if (!$numeral || !is_string($numeral))
  throw new \Exception("Invalid Roman numeral.");

$num = strtoupper(trim($numeral));
$nbr = 0;

if (ROMAN_VERBOSE === true)
  echo $num.PHP_EOL;

$lastVal = 0;
$lastCount = 0;
$lastGlyph = '';
$sub = false;

for ($x = 0; $x < strlen($num); $x++) {
  $val = self::$lookup2[$num[$x]] ?? 0;

  if (ROMAN_VERBOSE === true) {
    echo "********* ENTERING x = ".$x." *********".PHP_EOL;
    echo "Value: ".$val.PHP_EOL;
    echo "Last Count: ".$lastCount.PHP_EOL;
    echo "Last Value: ".$lastVal.PHP_EOL;
    echo "Glyph: ".$num[$x].PHP_EOL;
    echo "Last Glyph: ".$lastGlyph.PHP_EOL;
    echo "Current Number: ".$nbr.PHP_EOL;
    echo "Subtract: ".($sub !== false ? "Y" : "N").PHP_EOL;
    echo PHP_EOL;
  }

  if ($val == 0)
    throw new \Exception("Invalid Roman numeral.");
  if ($lastVal == 0) {
    $lastCount = 1;
    $lastVal = $val;
    $lastGlyph = $num[$x];
  } else if ($lastVal == $val) {
    $lastCount += 1;
    $sub = false;
  } else {
    if ($num[$x] == 'V' || $num[$x] == 'L' || $num[$x] == 'D')
      $sub = false;
    $nbr += ($sub === true ? -1 : 1) * ($lastVal * $lastCount);
    $sub = ($lastVal > $val);
    if ($num[$x] == 'V' || $num[$x] == 'L' || $num[$x] == 'D')
      $sub = false;
    $lastCount = 1;
    $lastVal = $val;

    if ($sub) {
      if ($lastGlyph === 'I' && $num[$x] !== 'V' && $num[$x] !== 'X')
        throw new \Exception("Invalid roman numeral.");
      if ($num[$x] !== 'L' && $num[$x] !== 'M' && $num[$x] !== 'C' && $lastGlyph == 'X')
        throw new \Exception("Invalid roman numeral.");
    }
    $lastGlyph = $num[$x];
  }

  if (ROMAN_VERBOSE === true) {
    echo "********* LEAVING x = ".$x." *********".PHP_EOL;
    echo "Value: ".$val.PHP_EOL;
    echo "Last Count: ".$lastCount.PHP_EOL;
    echo "Last Value: ".$lastVal.PHP_EOL;
    echo "Glyph: ".$num[$x].PHP_EOL;
    echo "Last Glyph: ".$lastGlyph.PHP_EOL;
    echo "Current Number: ".$nbr.PHP_EOL;
    echo "Subtract: ".($sub !== false ? "Y" : "N").PHP_EOL;
    echo PHP_EOL;
  }
}
return $nbr + ($sub === true ? -1 : 1) * ($lastVal * $lastCount);
}
}

echo RomanNumeral::toNumber("DLXVIII").PHP_EOL;  // should be 568
echo RomanNumeral::toNumber("MMMCMXCIX").PHP_EOL; // should be 3999
echo RomanNumeral::toNumber("DLXIVIII").PHP_EOL;  // throws exception
?>

字符串

kognpnkq

kognpnkq7#

for循环后调用romantoint

def checkIfRomanNumeral(numeral):
     """Controls that the userinput only contains valid roman numerals"""
     numeral = numeral.upper()
     validRomanNumerals = ["M", "D", "C", "L", "X", "V", "I"]
     for letters in numeral:
        if letters not in validRomanNumerals:
            print("Sorry that is not a valid roman numeral")
            return False
     romanToInt(numeral)

字符串

相关问题