好吧,我需要一个MySQL的函数,将转换为罗马数字字符串:
EG HKSTSVI
到其阿拉伯语的编号等同。它的一个漫长的故事,为什么我需要它,我只是做。
基于一个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$$
不知道为什么你的心不是工作,但谷歌搜索是快,我想出了这个链接:
http://forge.mysql.com/tools/tool.php?id=107
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(inRoman);
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;
END
我修改由瓦伦丁提供的功能,使其多了几分稳健。
现在:1)修剪出白色空间做罗马数字转换之前。 2)检查任何字符不是罗马数字输入文本,并返回-1,如果是这种情况。
这样的:
SELECT fromRoman('iv'), fromRoman('Mxii'), fromRoman(' iX'), fromRoman('xi '), fromRoman('Hi');
产量:
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