MySQL自定义函数将罗马数字转换为阿拉伯语

MySQL自定义函数将罗马数字转换为阿拉伯语,mysql,function,arabic,roman-numerals,Mysql,Function,Arabic,Roman Numerals,好的,我需要一个MySQL函数来转换罗马数字字符串: e、 g.XXCVI 转换为阿拉伯语的等效编号。关于我为什么需要它,说来话长,我只是需要 基于某人发布的一个PHP函数,我创建了以下MySQL函数,但它似乎在无休止地运行,我不知道为什么。(我可能太累了) 有人知道我的函数有什么问题吗,或者有更有效的方法将罗马数字字符串转换成阿拉伯数字吗 DROP FUNCTION IF EXISTS `romeToArabic`$$ CREATE DEFINER=`root`@`localhost` FUN

好的,我需要一个MySQL函数来转换罗马数字字符串:

e、 g.XXCVI

转换为阿拉伯语的等效编号。关于我为什么需要它,说来话长,我只是需要

基于某人发布的一个PHP函数,我创建了以下MySQL函数,但它似乎在无休止地运行,我不知道为什么。(我可能太累了)

有人知道我的函数有什么问题吗,或者有更有效的方法将罗马数字字符串转换成阿拉伯数字吗

DROP FUNCTION IF EXISTS `romeToArabic`$$
CREATE DEFINER=`root`@`localhost` FUNCTION `romeToArabic`(roman_in VARCHAR(64)) RETURNS int(11)
BEGIN
  DECLARE numeral VARCHAR(2);
  DECLARE int_val INT;
  DECLARE roman VARCHAR(64);
  DECLARE res INT;
  DECLARE no_more_rows BOOLEAN;
  DECLARE num_rows INT DEFAULT 0;
  DECLARE roman_cur CURSOR FOR SELECT num, val FROM roman_numeral ORDER BY id;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
  SET roman = UPPER(roman_in);
  SET res = 0;

  DROP TEMPORARY TABLE IF EXISTS roman_numeral;
  CREATE TEMPORARY TABLE roman_numeral (
      `id` INT(8) NOT NULL AUTO_INCREMENT,
      `num` varchar(2) DEFAULT NULL,
      `val` int(8) NOT NULL, PRIMARY KEY (id)) ENGINE=MyISAM;

  INSERT INTO roman_numeral (num, val) VALUES ('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);

  OPEN roman_cur;
  SELECT FOUND_ROWS() INTO num_rows;

 the_loop:
  LOOP
    FETCH  roman_cur INTO   numeral, int_val;
    IF no_more_rows THEN CLOSE roman_cur;
      LEAVE the_loop;
    END IF;

    WHILE INSTR(roman, numeral) = 1 DO
      SET res = res + int_val;
      SET roman = SUBSTRING(roman, LENGTH(numeral));
    END WHILE;

  END LOOP the_loop;
  IF res > 0 THEN
    RETURN res;
  ELSE
    RETURN -1;
  END IF;
END$$

我不知道你为什么不工作,但谷歌搜索速度很快,我找到了以下链接:

CREATE FUNCTION fromroam(inRoman varchar(15))返回整数
开始
声明数字字符(7)默认为“IVXLCDM”;
申报数字罐头;
声明先前的INT默认值为0;
声明当前INT;
声明sum INT默认为0;
设置inRoman=上限(inRoman);
而长度(单位:阿曼)>0 DO
设置数字:=定位(右(罗马,1),数字)-1;
设定电流:=POW(10,楼层(数字/2))*POW(5,模块(数字,2));
设置总和:=总和+功率(-1,电流<先前)*电流;
设置前一个:=当前;
设置inRoman=左侧(inRoman,长度(inRoman)-1);
结束时;
回报金额;
结束

我修改了Valentin提供的函数,使其更加健壮

现在: 1) 在进行罗马数字转换之前修剪空白。 2) 检查传入文本中是否有非罗马数字的字符,如果是这种情况,则返回-1

以便: 选择fromroam('iv')、fromroam('Mxii')、fromroam('iX'), fromroam('xi')、fromroam('Hi')

收益率: 4 1012 9 11-1

CREATE函数FROMAN(inRoman varchar(15))返回整数 开始
声明数字字符(7)默认为“IVXLCDM”; 申报数字罐头; 声明先前的INT默认值为0; 声明当前INT; 声明sum INT默认为0

SELECT fromRoman('iv'), fromRoman('Mxii'), fromRoman(' iX'), fromRoman('xi '), fromRoman('Hi');
SET inRoman=上部(修剪(inRoman));
如果不在阿曼REGEXP“[^IVXLCDM]+”中,则
而长度(单位:阿曼)>0 DO
设置数字:=定位(右(罗马,1),数字)-1;
设定电流:=POW(10,楼层(数字/2))*POW(5,模块(数字,2));
设置总和:=总和+功率(-1,电流<先前)*电流;
设置前一个:=当前;
设置inRoman=左侧(inRoman,长度(inRoman)-1);
结束时;
回报金额;
其他的
返回-1;
如果结束;
结束

我知道这个问题得到了完美的回答,也许这应该是一个评论,但我来这里是为了寻找相反的过程,从罗马到阿拉伯语,所以我有这个函数:

4 1012 9 11 -1
CREATE函数`toRoman`(inArabic int unsigned)返回varchar(15)字符集
开始
声明数字字符(7)默认为“IVXLCDM”;
声明stringInUse字符(3);
声明位置tinyint默认为1;
声明当前数字tinyint;
声明returnValue VARCHAR(15)为默认值“”;
如果(inArabic>3999),则返回“溢出”;如果结束;
如果(inArabic=0),则返回“N”;如果结束;
当位置=5时,
重复(子串(数字,位置*2-1,1),模块(当前数字,5))
)
完,,
返回值);
设置位置:=位置+1;
结束时;
返回值;
结束

谢谢!这比我写的要有效得多!不知怎的,我以前在谷歌上搜索时并没有把它拉上来,但这正是我所需要的! 4 1012 9 11 -1 CREATE FUNCTION fromRoman (inRoman varchar(15)) RETURNS integer DETERMINISTIC BEGIN
DECLARE numeral CHAR(7) DEFAULT 'IVXLCDM'; DECLARE digit TINYINT; DECLARE previous INT DEFAULT 0; DECLARE current INT; DECLARE sum INT DEFAULT 0;

  SET inRoman = UPPER(TRIM(inRoman));
  IF NOT inRoman REGEXP '[^IVXLCDM]+' THEN
    WHILE LENGTH(inRoman) > 0 DO
    SET digit := LOCATE(RIGHT(inRoman, 1), numeral) - 1;
    SET current := POW(10, FLOOR(digit / 2)) * POW(5, MOD(digit, 2));
    SET sum := sum + POW(-1, current < previous) * current;
    SET previous := current;
    SET inRoman = LEFT(inRoman, LENGTH(inRoman) - 1);
    END WHILE;

    RETURN sum;
  ELSE
    RETURN -1;
  END IF;
END
CREATE FUNCTION `toRoman`(inArabic int unsigned) RETURNS varchar(15) CHARSET latin1 DETERMINISTIC
BEGIN
    DECLARE numeral CHAR(7) DEFAULT 'IVXLCDM';

    DECLARE stringInUse CHAR(3);
    DECLARE position tinyint DEFAULT 1;
    DECLARE currentDigit tinyint;

    DECLARE returnValue VARCHAR(15) DEFAULT '';

    IF(inArabic > 3999) THEN RETURN 'overflow'; END IF;
    IF(inArabic = 0) THEN RETURN 'N'; END IF;

    WHILE position <= CEIL(LOG10(inArabic + .1)) DO
        SET currentDigit := MOD(FLOOR(inArabic / POW(10, position - 1)), 10);

        SET returnValue := CONCAT(
            CASE currentDigit
                WHEN 4 THEN CONCAT(SUBSTRING(numeral, position * 2 - 1, 1), SUBSTRING(numeral, position * 2, 1))
                WHEN 9 THEN CONCAT(SUBSTRING(numeral, position * 2 - 1, 1), SUBSTRING(numeral, position * 2 + 1, 1))
                ELSE CONCAT(
                    REPEAT(SUBSTRING(numeral, position * 2, 1), currentDigit >= 5),
                    REPEAT(SUBSTRING(numeral, position * 2 - 1, 1), MOD(currentDigit, 5))
                )
            END,
            returnValue);

        SET position := position + 1;
    END WHILE;
    RETURN returnValue;
END