コードのローマ字化


33

課題は、選択した言語でローマ数字を有効なコードにすることです。

それらは文字列または同様のものの内部に表示されるべきではありませんが、他のトークン、(アラビア語)数字などのリテラル、文字または文字列とまったく同じように機能します。または変数/メソッド/関数識別子など

たとえば、Javaでは、次のようiに初期化されたかのようにコンパイルして実行する必要があります42

int i = XLII;

数字の実際の解析は二次的なものなので、必要に応じてライブラリを使用できますが、これは人気のコンテストなので、創造性が奨励されます。

そのようなことがある場合、実際にローマ数字を使用する言語は使用できません。

がんばろう。


1
したがって、言語の拡張機能を作成して、新しい拡張機能を作成する必要がありますか?
ケンドールフレイ

4
私が使用したい言語はそのように拡張可能ではないので、私がしたい場合は文句を言うので、私も参加することはできません。
ケンドールフレイ

3
@KendallFreyソースはコンパイルして実行する必要があります。Javaの場合、ソースを編集し、プログラムでコンパイルする「コンパイラ」を作成できます。このようなコンパイルの1つの方法は、実行することですProcess
ジャスティン

1
ほとんどの言語では退屈そうです。たとえば、Pythonではast、ソースの解析に使用するスクリプトを書くだけです。1から3999までのローマ数字の定義をASTの上部に挿入します。すべてをコンパイルして実行します。プロセスを処理するコードを書くのは退屈です。
バクリウ14

2
@Bakuriuとあなたのコメントも退屈です。これは人気のコンテストなので、何か楽しいことを考えてみてください。ここには、(スクリプト言語をコンパイルするよりも)想像力豊かな素晴らしい答えがいくつかあると思います。
daniero 14

回答:


40

C

4000以上には標準的な表記法がないため、ローマ数字は非常に多く、特にコードに未定義の動作があるという事実に問題がない場合、プリプロセッサは素晴らしい解凍ツールです。

enum{_
#define a_
#define d_
#define g_
#define j_
#define a(x)c(x)b
#define b(x)c(x)a
#define c(x)x,
#define d(x)f(x)e
#define e(x)f(x)d
#define f(x)m(a(x)(x##I)(x##II)(x##III)(x##IV)(x##V)(x##VI)(x##VII)(x##VIII)(x##IX))
#define g(x)i(x)h
#define h(x)i(x)g
#define i(x)m(d(x)(x##X)(x##XX)(x##XXX)(x##XL)(x##L)(x##LX)(x##LXX)(x##LXXX)(x##XC))
#define j(x)l(x)k
#define k(x)l(x)j
#define l(x)m(g(x)(x##C)(x##CC)(x##CCC)(x##CD)(x##D)(x##DC)(x##DCC)(x##DCCC)(x##CM))
#define m(x)n(x)
#define n(...)__VA_ARGS__##_
m(j()(M)(MM)(MMM))
};

これは、からIまでのすべてのローマ数字MMMCMXCIXを列挙定数として定義し、プラス_(好きなものに置き換えることができます)をゼロとして定義します。


12
絶対に素晴らしい、次のCリリース(C2X?)に<roman.h>として追加することを提案してください!%rおよび%Rのprintf形式で!

3
今まで、プリプロセッサの使用方法を知っていると思いました:| この列挙型の最小限の使用例で答えを更新できますか?
klingt.net 14

@YiminRongそしてscanf:) @ klingt.netあなたがどんな種類の例を探しているのか分かりません。かなり単純な一つはされるだろうint main() { return MMMCMXCIX - M - M - M - CM - XC - IX; }
HVD

私はこのアイデアが好きですが、定義された動作が非常に単純なのに、なぜ未定義の動作を選択したのですか?判断しないで、好奇心だけですか?
CasaDeRobison

1
@CasaDeRobison楽しみのために、主に。前処理時の未定義動作の非常に少数のケースの1つであり、現在のコンパイラーによってエラーとしてフラグが立てられておらず、今後もそうなる可能性は低いため、気に入っています。有用なコードでそのようなものを書くことはありませんが、ここに投稿されたコードは有用なものではありません。
hvd

15

ルビー

def Object.const_missing(const)
  i = const.to_s
  if i =~ /^[IVXLCDM]+$/
    #http://codegolf.stackexchange.com/questions/16254/convert-arbitrary-roman-numeral-input-to-integer-output
    %w[IV,4 IX,9 XL,40 XC,90 CD,400 CM,900 I,1 V,5 X,10 L,50 C,100 D,500 M,1000].map{|s|k,v=s.split ?,;i.gsub!(k,?++v)}
    eval(i)
  else
    super
  end
end

(大文字の)ローマ数字は、10進数の同等物と同様に解析されるようになりました。唯一の問題は、それらがまだ割り当て可能であるということです。できますがX = 9、できません10 = 9。私はそれを修正する方法があるとは思わない。


1
これは完璧です。割り当ての問題は問題ではありません。割り当てを使用して、あらゆる種類の愚かなことを行うことができます。
daniero 14

12

JavaScript(ES6)

Proxyローマ数字をキャッチするために使用します。

JSFiddle上のFirefox(最新)でテスト可能。実装が壊れている
ため、Chrome(Traceurを使用)ではテストできませんProxy

// Convert roman numeral to integer.
// Borrowed from http://codegolf.stackexchange.com/a/20702/10920
var toDecimal = (s) => {
  var n = 0;
  var X = {
    M: 1e3, CM: 900, D: 500, CD: 400, C: 100, XC: 90, 
    L: 50,  XL: 40,  X: 10,  IX: 9,   V: 5,   IV: 4,  I: 1
  };

  s.replace(/[MDLV]|C[MD]?|X[CL]?|I[XV]?/g, (d) => n += X[d]);
  return n;
};

// Whether a string is a valid roman numeral.
var isRoman = (s) => s.match(/^[MDCLXVI]+$/);

// Profixy global environment to catch roman numerals.
// Since it uses `this`, global definitions are still accessible.
var romanEnv = new Proxy(this, {
  get: (target, name) => isRoman(name) ? toDecimal(name) : target[name],
  set: (target, name, value) => isRoman(name) ? undefined : (target[name] = value),
  has: (target, name) => isRoman(name) || name in target,
  hasOwn: (target, name) => name in target
});

使用法:

with (romanEnv) {
  var i = MIV + XLVIII;
  console.log(i); // 1052
}

10

C&C ++(更新された回答)

コメントで見たように、私の元のソリューションには2つの問題がありました。

  1. オプションのパラメータは、C99以降の言語ファミリの標準でのみ利用可能です。
  2. enum定義の末尾のコンマもC99以降に固有です。

古いプラットフォームで動作するようにコードをできるだけ汎用的にしたかったので、私はそれをもう一度突き止めることにしました。以前よりも長くなりますが、C89 / C90互換モードに設定されたコンパイラーおよびプリプロセッサーで動作します。すべてのマクロには、ソースコードで適切な数の引数が渡されますが、これらのマクロは「展開」されて何もないことがあります。

Visual C ++ 2013(バージョン12)は、パラメーターの欠落に関する警告を発しますが、mcpp(標準への高い準拠を主張するオープンソースプリプロセッサー)もgcc 4.8.1(-std = iso9899:1990 -pedantic-errorsスイッチ付き)も発しません事実上空の引数リストを持つマクロ呼び出しの警告またはエラー。

関連する標準(ANSI / ISO 9899-1990、6.8.3、マクロ置換)を確認した後、これが非標準と見なされるべきではないという十分な曖昧性があると思います。「関数のようなマクロの呼び出しにおける引数の数は、マクロ定義のパラメーターの数と一致しなければならない...」。マクロを呼び出すために必要な括弧(および複数のパラメーターの場合はコンマ)が配置されている限り、空の引数リストを除外するようには見えません。

末尾のコンマの問題については、列挙に余分な識別子を追加することで解決されます(私の場合、MMMMは、ローマ数字の順序付けの受け入れられた規則に従わなくても、識別子が3999に従うのと同じくらい合理的だと思われます正確に)。

少し簡潔なソリューションには、列挙を移動し、マクロを別のヘッダーファイルにある別のヘッダーファイルにサポートすることと、名前空間の汚染を避けるために使用直後のマクロ名のundefを使用することが含まれます。間違いなく、より良いマクロ名も選択する必要がありますが、これは当面のタスクには十分です。

更新されたソリューションに続いて、元のソリューション:

#define _0(i,v,x)
#define _1(i,v,x) i
#define _2(i,v,x) i##i
#define _3(i,v,x) i##i##i
#define _4(i,v,x) i##v
#define _5(i,v,x) v
#define _6(i,v,x) v##i
#define _7(i,v,x) v##i##i
#define _8(i,v,x) v##i##i##i
#define _9(i,v,x) i##x

#define k(p,s) p##s,
#define j(p,s) k(p,s)
#define i(p) j(p,_0(I,V,X)) j(p,_1(I,V,X)) j(p,_2(I,V,X)) j(p,_3(I,V,X)) j(p,_4(I,V,X)) j(p,_5(I,V,X)) j(p,_6(I,V,X)) j(p,_7(I,V,X)) j(p,_8(I,V,X)) j(p,_9(I,V,X))
#define h(p,s) i(p##s)
#define g(p,s) h(p,s)
#define f(p) g(p,_0(X,L,C)) g(p,_1(X,L,C)) g(p,_2(X,L,C)) g(p,_3(X,L,C)) g(p,_4(X,L,C)) g(p,_5(X,L,C)) g(p,_6(X,L,C)) g(p,_7(X,L,C)) g(p,_8(X,L,C)) g(p,_9(X,L,C))
#define e(p,s) f(p##s)
#define d(p,s) e(p,s)
#define c(p) d(p,_0(C,D,M)) d(p,_1(C,D,M)) d(p,_2(C,D,M)) d(p,_3(C,D,M)) d(p,_4(C,D,M)) d(p,_5(C,D,M)) d(p,_6(C,D,M)) d(p,_7(C,D,M)) d(p,_8(C,D,M)) d(p,_9(C,D,M))
#define b(p) c(p)
#define a() b(_0(M,N,O)) b(_1(M,N,O)) b(_2(M,N,O)) b(_3(M,N,O))

enum { _ a() MMMM };

#include <stdio.h>

int main(int argc, char** argv)
{
    printf("%d", MMMCMXCIX * MMMCMXCIX);
    return 0;
}

元の答え(最初の6つのアップ投票を受け取ったので、誰もこれをもう一度投票しない場合、私の更新されたソリューションがアップ投票を得たとは思わないでください):

以前の答えと同じ精神ではなく、方法で行う必要があります(異なる環境は常にプリプロセッサのいくつかの側面には同意しないが)だけ定義された動作を使用して移植可能。一部のパラメーターをオプションとして扱い、他のパラメーターを無視します__VA_ARGS__。C++など、マクロをサポートしないプリプロセッサーで動作するはずです。また、トークンを貼り付ける前に間接マクロを使用してパラメーターが展開されるようにし、最後に短くなり、読みやすくなります(しかし、それはまだトリッキーで、おそらく読みやすくなく、ただ簡単です):

#define g(_,__) _, _##I, _##II, _##III, _##IV, _##V, _##VI, _##VII, _##VIII, _##IX,
#define f(_,__) g(_,)
#define e(_,__) f(_,) f(_##X,) f(_##XX,) f(_##XXX,) f(_##XL,) f(_##L,) f(_##LX,) f(_##LXX,) f(_##LXXX,) f(_##XC,)
#define d(_,__) e(_,)
#define c(_,__) d(_,) d(_##C,) d(_##CC,) d(_##CCC,) d(_##CD,) d(_##D,) d(_##DC,) d(_##DCC,) d(_##DCCC,) d(_##CM,)
#define b(_,__) c(_,)
#define a       b(,) b(M,) b(MM,) b(MMM,)
enum { _ a };

1
+1、ただし、空のマクロ引数の使用、および列挙子リストの末尾のカンマは、どちらもC99とC ++ 11の新機能であり、C99とC ++ 11は両方ともサポートしてい__VA_ARGS__ます。
hvd

あなたが正しくない場合はダン!私はこれをこれまで拡張機能として使用しているのを見てきました。まぁ。:)
CasaDeRobison 14

8

Common Lisp

以下は、このように使用できるマクロを作成した方法のかなり長い説明です。

(roman-progn
  (+ XIV XXVIII))

Common Lispでマクロが呼び出されると、マクロは基本的に関数のように機能し、引数が評価される前に受け取られるだけです。実際、Common Lispではコードは単なるデータであるため、受け取るものは、構文解析されていない構文ツリーを表す(ネストされた)リストであり、何でもやりたいことができ、コンパイル時に行われます。

ヘルパー関数

計画の最初のステップは、このツリーを取得し、ローマ数字のように見えるものをスキャンします。これはLispであり、やや機能的にやってみましょう。ツリーを深くトラバースし、提供された関数searchpがtrue を返すすべてのオブジェクトを返す関数が必要です。これは(半)末尾再帰です。

(defun deep-find-all (searchp tree &optional found)
  (if (null tree)
    found
    (let* ((item (car tree))
           (new-found (if (consp item)
                        (deep-find-all searchp item found)
                        (if (funcall searchp item)
                          (cons item found)
                          found))))

      (deep-find-all searchp (cdr tree) new-found))))

次に、Rosetta Codeの好意により、ローマ数字を解析するためのコードをいくつか示します。

(defun mapcn (chars nums string)
  (loop as char across string as i = (position char chars) collect (and i (nth i nums))))

(defun parse-roman (R)
  (loop with nums = (mapcn "IVXLCDM" '(1 5 10 50 100 500 1000) R)
        as (A B) on nums if A sum (if (and B (< A B)) (- A) A)))

実際のマクロ

構文木(body)を取得し、ディープファインオールプロシージャで検索し、見つかったローマ数字を何らかの方法で使用可能にします。

(defmacro roman-progn (&body body)
  (let* ((symbols (deep-find-all (lambda (sym)
                                   (and
                                     (symbolp sym)
                                     (loop for c across (string sym)
                                           always (find c "IVXLCDM")))) body))
         (parsed-romans (mapcar (lambda (sym)
                                  (list sym (parse-roman (string sym)))) symbols)))

    (if parsed-romans
      `(let (,@parsed-romans)
         ,@body)  
      `(progn
         ,@body))))

それで、何1 + 2 + 3 + (4 * (5 + 6)) + 7ですか?

(roman-progn
  (+ I II III (* IV (+ V VI)) VII))
=> 57

そして、マクロが呼び出されたときに実際に何が起こったかを確認するには:

(macroexpand-1 +)
=> (LET ((VII 7) (VI 6) (V 5) (IV 4) (III 3) (II 2) (I 1))
   (+ I II III (* IV (+ V VI)) VII))

7

ルア

setmetatable(_G, {
    __index = function(_, k)
        if k:match"^[IVXLCDM]*$" then
            local n = 0
            for _, v in ipairs{{IV = 4}, {IX = 9}, {I = 1}, {V = 5}, {XL = 40}, {X = 10}, {XC = 900}, {CD = 400}, {CM = 900}, {C = 100}, {D = 500}, {M = 1000}} do
                local p, q = next(v)
                local r
                k, r = k:gsub(p, "")
                n = n + r * q
            end
            return n
        end
    end
})

グローバルテーブルの単純なフォールバック__index。gsubを使用した実際の変換は、想像していたよりもずっときれいでした。


5

追記

私はCをフォローしようとしましたが、理解できませんでした。だから私はこのようにしました:

/strcat{
    2 copy length exch length add string % 1 2 3 
    3 2 roll % 2 3 1 
    2 copy 0 exch putinterval % 2 3 1 
    2 copy length % 2 3 1 3 n(1)
    5 4 roll putinterval % 3 1 
    pop 
}def
/S{
    dup length string cvs 
} def 
[
/u {/ /I /II /III /IV /V /VI /VII /VIII /IX}
/t {/ /X /XX /XXX /XL /L /LX /LXX /LXXX /XC}
/h {/ /C /CC /CCC /CD /D /DC /DCC /DCCC /CM}
/m {/ /M /MM /MMM /MMMM}
>>begin
[0
[
[m]{ % M*
    S   
    [h]{ % M* H*
        S
        [t]{ % M* H* T*
            S
            [u]{ % M* H* T* U*
                S
                4 copy
                strcat strcat strcat % M* H* T* U* M*H*T*U*
                5 1 roll % M*H*T*U* M* H* T* U*
                pop % (M*H*T*U*)* M* H* T*
            }forall
            pop % (M*H*T*U*)** M* H*
        }forall
        pop % (M*H*T*U*)*** M*
    }forall
    pop % (M*H*T*U*)****
}forall
]
{exch dup 1 add}forall pop>>end begin

Postscriptにはありませんがenum、連続した整数値で辞書を作成し、それらを配列に折り畳むことができます。これにより、すべての文字列を順番に生成する問題が軽減されます。これは、4つのネストされたループで連結することによって行われます。そのため、すべての文字列を生成してから、各文字列を増加するカウンタ値でインターリーブし、スタック上で長い一連の<string> <int>ペアを生成し、<<...でラップし>>て辞書オブジェクトを生成します。

プログラムは、ローマ数字のすべての名前を対応する値にマッピングする辞書を作成してインストールします。したがって、ソーステキストで名前に言及すると、自動名前検索が呼び出され、スタック上に整数値が生成されます。

II IV MC pstack

プリント

2
4
600

4

Smalltalk(Smalltalk / X)(87/101文字)

もちろん、パーサーのトークナイザーを簡単に変更できます(クラスライブラリの一部であり、変更可能なため、常に存在します)が、課題は特定のコンテキストの評価のみに影響を与えることです。システムは通常どおり動作します。

バージョン1:

評価名前空間にいくつかの変数を定義します。したがって、これは対話型doIt(別名evals)に影響します。

(1 to:3999) do:[:n | 
    Workspace workspaceVariables at:(n romanPrintString asUppercase) put:n]

その後、私は行うことができます(doItで、コンパイルされたコードではありません):

   |a b|
   a := MMXIV.
   b := V.
   a + b

-> 2019

注意:101文字には空白が含まれています。実際には、87文字で実行できます。
また、グローバルなSmalltalk名前空間で定義すると、コンパイル済みのコードにもこれらの定数が表示されます。

バージョン2:

methodWrapperフックを使用します。これにより、既存のコードを再コンパイルせずにラップできます。以下は、パーサーのトークナイザーをラップして、スキャンされるローマ字の識別子を探し、整数にします。トリッキーな部分は、呼び出し側コンテキストがローマ帝国からのものかどうかを動的に検出することです。これは、クエリ信号を使用して行われます(技術的には続行可能な例外です)。

クエリを定義します。

InRomanScope := QuerySignal new defaultAnswer:false.

そのため、いつでもデフォルトでfalseを取得するように要求できます(「InRomanScopeクエリ」)。

次に、スキャナーのcheckIdentifierメソッドをラップします。

MessageTracer 
    wrapMethod:(Scanner compiledMethodAt:#checkForKeyword:)
    onEntry:nil
    onExit:[:ctx :ret |
        InRomanScope query ifTrue:[
            |scanner string token n|

            scanner := ctx receiver.
            string := ctx argAt:1.
            (n := Integer readFromRomanString:string onError:nil) notNil
            ifTrue:[
                scanner "/ hack; there is no setter for those two
                    instVarNamed:'tokenType' put:#Integer;
                    instVarNamed:'tokenValue' put:n.
                true
            ] ifFalse:[
                ret
            ].
        ] ifFalse:[
            ret
        ]
    ].

これで、ローマ帝国にいない限り、スキャナーは通常どおり動作します。

InRomanScope answer:true do:[
    (Parser evaluate:'MMDXXV') printCR.
].

-> 2525

コードをコンパイルすることもできます。

Compiler 
    compile:'
        inTheYear2525
            ^ MMDXXV
    '
    forClass:Integer.

よい試み; しかし、これは構文エラーで失敗します(これはまさに私たちが望むものです)。ただし、ローマ帝国では、以下をコンパイルできます。

InRomanScope answer:true do:[

    Compiler 
        compile:'
            inTheYear2525
                ^ MMDXXV
        '
        forClass:Integer.
]

そして今、私たちはローマの内側と外側から整数(そのメッセージを送信する)を尋ねることができます

(1000 factorial) inTheYear2525

-> 2525


Smalltalkを見るのは嬉しいです!

4

Haskell、テンプレートHaskellおよびroman-numeralsでメタプログラミングを使用:

{-# LANGUAGE TemplateHaskell #-}
import Data.Char (toLower)
import Language.Haskell.TH
import Text.Numeral.Roman

$( mapM (\n -> funD (mkName . map toLower . toRoman $ n)
                    [ clause [] (normalB [| n |]) []]) $ [1..1000 :: Int] )

main = print xlii

Haskellは、コンストラクターの大文字で始まる識別子を予約しているため、小文字を使用しました。


4

J-78文字

これは、他のソリューションと同様に、MMMCMXCIX = 3999になります。

(}.,;L:1{M`CDM`XLC`IVX('';&;:(_1,~3#.inv]){' ',[)&.>841,3#79bc5yuukh)=:}.i.4e3

それを分解します(Jが括弧で置き換えられない限り、通常、右から左に読み取られることを思い出してください):

  • M`CDM`XLC`IVX-4箱の手紙。これらの文字のインデックスに数値配列を使用して、ローマ数字のサブワードを作成します。
  • 841,3#79bc5yuukh -これは、厳密にエンコードされた数値データです。*
  • (_1,~3#.inv]) -これは、3進数で展開し、-1を追加することにより、上記のデータをデコードします。
  • ('';&;:(...){' ',[)&.>-左側&.>の数字と右側のボックス()を組み合わせて、数字の配列をデコードし、それらを使用して文字にインデックスを付けます。文字リストにスペース文字を追加することにより、0をスペースとして扱います。このプロシージャはI II III IV V VI VII VIII IX、やなどの単語のリストを作成しますM MM MMM
  • {-言葉でいっぱいのこれらの4つの箱のデカルト積を取ります。これで、すべてのローマ数字の4D配列ができました。
  • }.,;L:1-すべてをローマ数字の単一の1Dリストに実行し、エラーが発生するため、先頭の空の文字列を削除します。(L:Jゴルフでは珍しい光景です!通常、これほど多くのレベルのボクシングはありません。)
  • }.i.4e3- エンドポイントを除く 0〜4000の整数。
  • 最後に、すべてをグローバルな割り当てにまとめ=:ます。Jを使用すると、計算された複数の割り当ての形式として、ボックス化された名前のリストをLHSに保持できるため、これで問題なく動作します。

J名前空間は、ローマ数字を表す変数でいっぱいになりました。

   XCIX
99
   MMCDLXXVIII
2478
   V * LXIII   NB. 5*63
315
   #4!:1]0     NB. How many variables are now defined in the J namespace?
3999

*後で29 374074030998を基数3で読み取る必要があります。そのため、30以下の数字を使用して基数79で表現できることがあります。 az)。これにより、10進数で3文字節約されます。


3

Python

他の答えと同じように、アイデアはシンプルです。ただし、グローバルネームスペースを汚染しないために、簡潔にするために、コンテキストマネージャが使用されます。これは、使用する予定のローマ数字の範囲を事前に宣言する必要があるという制限も課します。

注:単純にするために、車輪を再発明するためではなく、Roman pythonパッケージを利用しました

実装

class Roman(object):
    memo = [0]
    def __init__(self, hi):
        import rome
        if hi <= len(RomanNumericals.memo):
            self.romans = Roman.memo[0:hi]
        else:
            Roman.memo += [str(rome.Roman(i))
                    for i in range(len(Roman.memo),
                            hi+1)]
            self.romans = Roman.memo
    def __enter__(self):
        from copy import copy
        self.saved_globals = copy(globals())
        globals().update((v,k) for k,v in enumerate(self.romans[1:], 1))
    def __exit__(self,*args ):
        globals().clear()
        globals().update(self.saved_globals)

デモ

with Roman(5):
    with Roman(10):
        print X
    print V
    print X


10
5

Traceback (most recent call last):
  File "<pyshell#311>", line 5, in <module>
    print X
NameError: name 'X' is not defined

3

Python

これはおそらくPythonを使用した最も簡単なソリューションです。

ns = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
ls = 'M CM D CD C XC L XL X IX V IV I'.split()
for N in range(1, 4000):
    r=''
    p=N
    for n,l in zip(ns,ls):
        while p>=n:
            r+=l
            p-=n
    exec('%s=%d'%(r,N))


i, j = XIX, MCXIV
print i, j

3
使用する方がglobals()[var] = valueよりexec()
Ramchandra Apte

3

D

Dのコンパイル時関数評価を使用する

import std.algorithm;
string numerals(){
    auto s = cartesianProduct(["","I","II","III","IV","V","VI","VII","VIII","IX"], 
                              ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"],
                              ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"],
                              ["","M","MM","MMM"]);
    s.popFront();//skip first
    char[] result="enum ";
    int i=1;
    foreach(p;s){
        result~=p[3]~p[2]~p[1]~p[0]~"="~i++~",";
    }
    result[$-1]=';';//replace last , with a ;
    return result.idup;
}
mixin(numerals());

3

APL(Dyalog APL)、77バイト

ローマ数字の最大長を要求し、すべての変数を定義します。

t'IVXLCDM',⊂⍬
{⍎⍕⍵'←',+/2(⊣ׯ1*<)/0,⍨(∊1 5∘ר10*⍳4)[t⍳⍵]}¨,/t[⍉8⊥⍣¯1⍳¯1+8*⎕]

t←tが取得します

'IVXLCDM', ローマ字の後に

 同封

 空のリスト

t[] インデックスt

 転置(正しい順序を取得するため)

8⊥⍣¯1 適切な幅のベース8表現

 最初のn個のインデックス。n

¯1+ より小さい

8*⎕ 8の数値入力のべき乗

,/ 行をフラット化する(各表現)

{ 次の匿名関数を各表現に適用します…

(t)[t⍳⍵]  内の引数の項目の位置に対応し、以下から選択します…

   入隊した

  1 5∘ר それぞれ1回と5回

  10* 10の累乗

  ⍳4 ゼロから3

0,⍨ ゼロを追加

2(…)/ 長さ2のスライドウィンドウごとに、次の匿名関数トレインを適用します…

  ⊣× 左引数回

  ¯1* 負の1のべき乗

  < 左引数が右引数より小さいかどうか

+/ 和

⍵'←', 引数(ローマ数字)と割り当て矢印を追加します

 フォーマット(数値をフラット化してテキストに変換)

 それを実行します(匿名関数の外部で割り当てを行います)

オンラインでお試しください!(最大長5を使用)


2

PHP

有効なローマ数字にはいくつかのルールがあります

  1. 低い値の前に最大値を書きます

  2. [I,X,C]次の2つの大きい値の前のみ減算します

  3. [I,X,C]次の2つの大きい値の前にdoubleを減算します

  4. [I,X,C]大きい値の前にdoubleを減算します

  5. 4 + 5を組み合わせる

オンライン版

ステップ1ルールを作成する

{"M":1000,"IM":999,"IIM":998,"XM":990,"XXM":980,"CM":900,"CCM":800,"D":500,"ID":499,"IID":498,"XD":490,"XXD":480,"CD":400,"C":100,"IC":99,"IIC":98,"XC":90,"XXC":80,"L":50,"IL":49,"IIL":48,"XL":40,"X":10,"IX":9,"IIX":8,"V":5,"IV":4,"I":1}

すべての有効なローマ数字のJSON出力です

$rule_sub_all=$rule_add=$rule_sub_simple=["M"=>1000,"D"=>500,"C"=>100,"L"=>50,"X"=>10,"V"=>5,"I"=>1];
foreach(["I","X","C"]as$roman_letter){
    $rule_sub_simple[$roman_letter.array_search($value=$rule_add[$roman_letter]*5,$rule_add)]=$value-$rule_add[$roman_letter];
    $rule_sub_simple[$roman_letter.array_search($value=$rule_add[$roman_letter]*10,$rule_add)]=$value-$rule_add[$roman_letter];
}
$rule_sub_lower_one=$rule_sub_double=$rule_sub_simple;
foreach(["I","X","C"]as$roman_letter){
    $rule_sub_double[$roman_letter.$roman_letter.array_search($value=$rule_add[$roman_letter]*10,$rule_add)]=$value-2*$rule_add[$roman_letter];

foreach($rule_add as$key=>$value){
    if($value>$rule_add[$roman_letter])$rule_sub_all[$roman_letter.$key]=$value-$rule_add[$roman_letter];
    if($value>5*$rule_add[$roman_letter])$rule_sub_all[$roman_letter.$roman_letter.$key]=$value-2*$rule_add[$roman_letter];
    if($value>10*$rule_add[$roman_letter])$rule_sub_lower_one[$roman_letter.$key]=$value-$rule_add[$roman_letter];
    }
}
arsort($rule_sub_all);
arsort($rule_sub_lower_one);
arsort($rule_sub_double);
arsort($rule_sub_simple);

ステップ2 3999までのすべてのルールのリストを作成します

$array_sub_lower_one=$array_sub_double=$array_sub_all=$array_add=$array_sub_simple=[];
for($i=1;$i<4000;$i++){
    $number_sub_all=$number_add=$number_sub_simple=$number_sub_double=$number_sub_lower_one=$i;
    $roman_letter_sub_all=$roman_letter_add=$roman_letter_sub_simple=$roman_letter_sub_double=$roman_letter_sub_lower_one="";
    foreach($rule_sub_all as$key=>$value){
        $roman_letter_sub_all.=str_repeat($key,$d=$number_sub_all/$value^0);$number_sub_all-=$value*$d;
        if(in_array($value,$rule_sub_lower_one)){
        $roman_letter_sub_lower_one.=str_repeat($key,$d=$number_sub_lower_one/$value^0);$number_sub_lower_one-=$value*$d;}    
        if(in_array($value,$rule_add)){
        $roman_letter_add.=str_repeat($key,$d=$number_add/$value^0);$number_add-=$value*$d;}
        if(in_array($value,$rule_sub_simple)){
        $roman_letter_sub_simple.=str_repeat($key,$d=$number_sub_simple/$value^0);$number_sub_simple-=$value*$d;}
        if(in_array($value,$rule_sub_double)){
        $roman_letter_sub_double.=str_repeat($key,$d=$number_sub_double/$value^0);$number_sub_double-=$value*$d;}
     }
    $array_sub_lower_one[$roman_letter_sub_lower_one]=$i;   
    $array_sub_all[$roman_letter_sub_all]=$i;
    $array_add[$roman_letter_add]=$i;
    $array_sub_simple[$roman_letter_sub_simple]=$i;
    $array_sub_double[$roman_letter_sub_double]=$i;
}

ステップ3定数を作成する

すべてのリストを結合し、定数を定義します

foreach(array_merge($array_add,$array_sub_simple,$array_sub_lower_one,$array_sub_double,$array_sub_all)as$key=>$value){ define($key,$value); }

出力

この例では、数8の複数の有効なバージョン

echo IIX *  VIII;

いいけど、どうやってこれを使うの?私はPHPに堪能ではありません。これにより、コードにローマ数字を書くことができる方法の例を教えてください。
ダニエロ

@Danieroこれでコードが機能するはずです
ヨルクヒュルサーマン

ああ、それは良いです:)
daniero

1

レボル

Rebol []

roman-dialect: func [
    {Dialect which allows Roman numerals as numbers (integer!)}
    block [block!]
    /local word w m1 m2 when-in-rome rule word-rule block-rule
  ][
    when-in-rome: does [
        if roman? w: to-string word [change/part m1 roman-to-integer w m2]
    ]

    word-rule:  [m1: copy word word! m2: (when-in-rome)]
    block-rule: [m1: any-block! (parse m1/1 rule)]
    rule:       [any [block-rule | word-rule | skip]]

    parse block rule
    do block
]

; couple of helper functions used in above parse rules

roman-to-integer: func [roman /local r eval] [
    r: [IV 4 IX 9 XL 40 XC 90 CD 400 CM 900 I 1 V 5 X 10 L 50 C 100 D 500 M 1000]
    eval: join "0" copy roman
    foreach [k v] r [replace/all eval k join " + " v]
    do replace/all to-block eval '+ '+
]

roman?: func [s /local roman-chars] [
    roman-char: charset "IVXLCDM"
    parse/case s [some roman-char]
]


roman-dialect [
    m: X + V
    print m
    print M + m  ; doesn't confuse the variable m with Roman Numeral M
    if now/year = MMXIV [print "Yes it is 2014"]
    for n I V I [
        print [rejoin [n "+" X "="] n + X]
    ]
]

出力:

15

1015

はい、2014年です

1 + 10 = 11

2 + 10 = 12

3 + 10 = 13

4 + 10 = 14

5 + 10 = 15


免責事項:Rebolでこれを行う他の(そしておそらくもっと良い!)方法があると確信しています。

PS。私のroman-to-integer機能は、ローマ数字文字列を数値に変換するためのhistocratの素敵なRubyアルゴリズムの音訳です。おかげで返されました!+1


1

ルア

local g={}
setmetatable(_G,g)
local romans = {I = 1,
                V = 5,
                X = 10,
                L = 50,
                C = 100,
                D = 500,
                M = 1000}
local larger = {    -- Precalced, for faster computing.
                I = "VXLCDM",
                V = "XLCDM",
                X = "LCDM",
                L = "CDM",
                C = "DM",
                D = "M",
                M = " " -- A space will never be found, and it prevents the pattern matcher from erroring.
}
local storedRomans = {}
function g:__index(key)
    if storedRomans[key] then
        return storedRomans[key]
    end
    if key:match"^[IVXLCDM]+$" then
        local n = 0
        local i = 1
        for s in key:gmatch"." do
            local N = romans[s]
            if key:find('['..larger[s]..']',i) then
                n = n - N
            else
                n = n + N
            end
            i = i + 1
        end
        storedRomans[key] = n
        return n
    end
end

これは、グローバルテーブルのメタテーブルに影響を与え、新しいインデックス関数を与えます。ローマ数字のみを含むグローバル変数が要求された場合、たとえばXVII解析されます。

テストが簡単。

print(XVII) -- 42
print(VI)   -- 6
print(III)  -- 3
print(MMM)  -- 3000

オンラインでお試しください!


1

VBA、204バイト

入力を受け取らず、実行時に、すべてのローマ数字の値を含むpubliclyにアクセス可能な宣言されたサブルーチンを作成します。これらの値は、Enumを参照せずに直接使用できます。EnumR

列挙は、1〜3999の値を保持します。

注:" 3行目と7行目の端末は、構文の強調表示のみを目的として含まれており、バイトカウントには寄与しません。

Public Sub i
Set c=ThisWorkbook.VBProject.VBComponents.Add(1).CodeModule
c.AddFromString"Public Enum R"
For n=1To 3999
c.AddFromString WorksheetFunction.Roman(n)&"="&n
Next
c.AddFromString"End Enum"
End Sub

非ゴルフと説明

Public Sub InitializeRomanNumerals()
    Dim c As CodeModule                                            ''  Dim CodeModule
    Set c=ThisWorkbook.VBProject.VBComponents.Add(1).CodeModule    ''  Create Module
    Let c.Parent.Name = "RomanNumeral_Module"                      ''  Name the Module
    Call c.AddFromString("Public Enum RomanNumerals")              ''  Declare the Enum
        For n=1To 3999Step 1                                       ''  Iter from 1 to 3999
            Call c.AddFromString(WorksheetFunction.Roman(n)&"="&n) ''  Add the Roman
                                                                   ''  Numeral to Enum
        Next n                                                     ''  Loop
    Call c.AddFromString("End Enum")                               ''  End The Enum
End Sub
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.