本当は正規表現を使うつもりだったものが、どうもうまくいかないので、自力でパーサを書くことにした。で、そのアルゴリズム検証のための下書き。
なんのかんの言ってもC++が一番なじんでいるので、C++で書いた。
一応意図どおりに動いているようなので、これを翻訳して使う予定。それはまた明日にでも…。
#include <iostream> #include <algorithm> #include <string> template<typename Iterator> std::pair<Iterator, int> asRomanNumeralDigit(Iterator begin, Iterator end, char ten, char five, char one) { Iterator i = begin; if((i != end) && (*i == one)) { ++i; if((i != end) && (*i == five)) { ++i; return std::make_pair(i, 4); } else if((i != end) && (*i == ten)) { ++i; return std::make_pair(i, 9); } else { int value = 1; while((value < 3) && (i != end) && (*i == one)) { ++value; ++i; } return std::make_pair(i, value); } } else if((i != end) && (*i == five)) { ++i; int value = 5; while((value < 8) && (i != end) && (*i == one)) { ++value; ++i; } return std::make_pair(i, value); } else { return std::make_pair(i, 0); } } template<typename Iterator> int asRomanNumeral(Iterator begin, Iterator end) { static const char M = 'M'; static const char D = 'D'; static const char C = 'C'; static const char L = 'L'; static const char X = 'X'; static const char V = 'V'; static const char I = 'I'; Iterator itr = begin; int m = 0; while((m < 3) && (itr != end) && (*itr == M)) { ++m; ++itr; } std::pair<Iterator, int> c = asRomanNumeralDigit(itr, end, M, D, C); std::pair<Iterator, int> x = asRomanNumeralDigit(c.first, end, C, L, X); std::pair<Iterator, int> i = asRomanNumeralDigit(x.first, end, X, V, I); if(i.first != end) { return 0; } return m * 1000 + c.second * 100 + x.second * 10 + i.second; } int main(int argc, char* argv[]) { for(int i = 1; i < argc; ++i) { std::cout << argv[i] << " => "; int result = asRomanNumeral(argv[i], argv[i] + std::strlen(argv[i])); if(result != 0) { std::cout << result << "\n"; } else { std::cout << "cannot express\n"; } } return 0; }
実行結果。
$ ./RomanNumeral I II III IV V VI VII VIII IX X L C D M IIII IIX MCMLXXIV MDCCCLXXXVIII MDCCCXXXIIII MMMM MMMCMXCIX I => 1 II => 2 III => 3 IV => 4 V => 5 VI => 6 VII => 7 VIII => 8 IX => 9 X => 10 L => 50 C => 100 D => 500 M => 1000 IIII => cannot express IIX => cannot express MCMLXXIV => 1974 MDCCCLXXXVIII => 1888 MDCCCXXXIIII => cannot express MMMM => cannot express MMMCMXCIX => 3999