3

わかりました。ローマ数字の文字列を変換するMySQL関数が必要です。

例: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$$
4

3 に答える 3

9

あなたが機能していない理由はわかりませんが、グーグルは高速で、次のリンクを思いつきました:

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
于 2011-11-04T05:50:38.207 に答える
1

Valentin が提供する関数を変更して、もう少し堅牢にしました。

1) ローマ数字変換を行う前に、空白を削除します。2) 着信テキストにローマ数字以外の文字がないかチェックし、そうである場合は -1 を返します。

そのような:

SELECT fromRoman('iv'), fromRoman('Mxii'), fromRoman('iX'),
       fromRoman('xi'), fromRoman('こんにちは');

収量:

4 1012 9 11 -1

    CREATE FUNCTION fromRoman (inRoman varchar(15)) RETURNS integer DETERMINISTIC
      始める
DECLARE 数値 CHAR(7) DEFAULT 'IVXLCDM'; DECLARE digit TINYINT; DECLARE 以前の INT DEFAULT 0; DECLARE 現在の 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

于 2011-11-05T14:49:14.567 に答える