코드 로마자


33

문제는 로마 숫자를 선택한 언어로 유효한 코드 로 만드는 것 입니다.

그들은해야 하지 다른 모든 토큰과 같은 문자열의 내부 또는 유사한 아무것도하지만, 일을 표시, 리터럴 등 (같은 아랍어 ) 숫자, 문자 또는 문자열; 또는 변수 / 방법 / 함수 식별자 등

예를 들어 Java에서는 다음과 같이 i초기화 된 것처럼 다음을 컴파일하고 실행 해야합니다 42.

int i = XLII;

숫자의 실제 구문 분석은 부차적이므로 원하는 경우 라이브러리를 사용할 수 있지만 이것은 인기 경연 대회이므로 창의성이 권장됩니다.

실제로 로마 숫자를 사용하는 언어가 있다면 언어를 사용할 수 없습니다.

행운을 빕니다.


1
언어에 대한 확장을 작성하여 새로운 언어를 만들어야합니까?
Kendall Frey

4
내가 사용하는 언어는 그렇게 확장 할 수 없으므로 참여할 수 없기 때문에 원하면 불만을 제기 할 것입니다.
Kendall Frey

3
@KendallFrey 소스는 컴파일하고 실행해야합니다. Java의 경우 소스를 편집 한 다음 프로그래밍 방식으로 컴파일 하는 "컴파일러"를 작성할 수 있습니다. 이러한 컴파일의 한 가지 방법은 다음을 실행하는 것입니다.Process
Justin

1
대부분의 언어에서 지루한 것 같습니다. 예를 들어 파이썬에서는 단순히 ast소스를 파싱 하는 데 사용하는 스크립트를 작성합니다 . AST의 맨 위에 1에서 3999까지의 로마 숫자 정의를 삽입하십시오. 전체를 컴파일하고 실행하십시오. 프로세스를 처리하는 코드를 작성하는 것은 지루합니다.
Bakuriu

2
@Bakuriu와 귀하의 의견도 지루합니다. 이것은 인기 경연 대회이므로 재미있는 것을 생각해보십시오. 스크립트 언어를 컴파일하는 것보다 더 상상력이 좋은 멋진 답변이 여기에 있다고 생각합니다.
daniero

답변:


40

기음

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))
};

이 모든 로마 숫자를 정의 IMMMCMXCIX열거 상수로, 플러스 _제로로 (당신이 좋아하는 무엇으로 대체 할 수있다).


12
절대적으로 훌륭합니다. <roman.h>와 같이 다음 C 릴리스 (C2X?)에 추가하십시오! % r 및 % R printf 형식으로!

3
나는 지금까지 전처리기를 사용하는 방법을 알고 있다고 생각했다. 이 열거 형의 최소 사용법 예제로 답변을 업데이트 할 수 있습니까?
klingt.net

@YiminRong 그리고 scanf:) @ klingt.net 어떤 종류의 예제를 찾고 있는지 잘 모르겠습니다. 꽤 간단한 것int main() { return MMMCMXCIX - M - M - M - CM - XC - IX; }
hvd

나는 그 아이디어를 좋아하지만 정의 된 행동이 상당히 단순 할 때 왜 정의되지 않은 행동을하기로 선택 했습니까? 판단하지 않고 궁금한가?
CasaDeRobison

1
@CasaDeRobison 주로 재미를 위해. 전처리 시간에 정의되지 않은 동작이 거의없는 경우 중 하나이므로 현재 컴파일러에서 오류로 표시되지 않으며 향후에는 없을 것입니다. 유용한 코드로 작성하지는 않았지만 여기에 게시 된 코드는 유용하지 않습니다. 어떻게 시도해야합니까?
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

12

자바 스크립트 (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 ++ (업데이트 된 답변)

의견에서 볼 수 있듯이 원래 솔루션에는 두 가지 문제가 있습니다.

  1. 선택적 매개 변수는 C99 이상의 언어 제품군 표준에서만 사용할 수 있습니다.
  2. 열거 형 정의의 후행 쉼표는 C99 이상에만 해당됩니다.

이전 플랫폼에서 작동하도록 코드를 가능한 한 일반적으로 만들고 싶었으므로 다른 코드를 사용하기로 결정했습니다. 이전보다 오래되었지만 C89 / C90 호환 모드로 설정된 컴파일러 및 전 처리기에서 작동합니다. 모든 매크로는 소스 코드에서 적절한 수의 인수로 전달되지만 때로는 해당 매크로가 아무 것도 확장되지 않습니다.

Visual C ++ 2013 (일명 버전 12)은 누락 된 매개 변수에 대한 경고를 표시하지만 mcpp (표준을 준수한다고 주장하는 오픈 소스 전 처리기) 또는 gcc 4.8.1 (-std = iso9899 : 1990 -pedantic-errors 스위치 사용)을 방출하지 않습니다. 효과적으로 빈 인수 목록이있는 매크로 호출에 대한 경고 또는 오류

관련 표준 (ANSI / ISO 9899-1990, 6.8.3, 매크로 대체)을 검토 한 후 이것이 비표준으로 간주되어서는 안될 모호성이 충분하다고 생각합니다. "함수 유사 매크로를 호출 할 때의 인수 수는 매크로 정의의 매개 변수 수와 일치해야합니다 ..." 매크로를 호출하는 데 필요한 괄호 (및 여러 매개 변수의 경우 쉼표)가있는 한 빈 인수 목록을 배제하지 않는 것 같습니다

후행 쉼표 문제는 열거에 추가 식별자를 추가하여 해결됩니다 (제 경우에는 로마 숫자 시퀀싱의 허용 규칙을 준수하지 않더라도 식별자가 3999를 따르는 것만 큼 합리적인 것처럼 보이는 MMMM) 정확하게).

약간 더 깨끗한 해결책은 다른 곳의 주석에 암시 된 것처럼 열거 형과 지원 매크로를 별도의 헤더 파일로 옮기고 네임 스페이스를 오염시키지 않도록 매크로 이름을 사용한 직후 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 2013

8

공통 리스프

다음은 내가 이와 같이 사용할 수있는 매크로를 만드는 방법에 대한 다소 긴 설명입니다.

(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))))

그런 다음 로제타 코드의 호의로 로마 숫자를 파싱하는 코드가 있습니다 .

(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

포스트 스크립트는 없지만 enum순차적 인 정수 값으로 사전을 구성하여 배열로 접을 수 있습니다. 이렇게하면 모든 문자열을 순서대로 생성하는 문제가 줄어 듭니다. 이는 4 개의 중첩 루프로 연결하여 수행됩니다. 그것은 모든 문자열을 생성 그렇다면, 긴 일련의 결과, 증가 카운터의 값과 각 스트링들을 인터리빙 <문자열> <INT> 래핑 된 스택 쌍 <<... >>사전 객체를 생성한다.

이 프로그램은 로마 숫자의 모든 이름을 해당 값에 매핑하는 사전을 구성하고 설치합니다. 따라서 소스 텍스트에 이름을 언급하면 ​​자동 이름 조회가 호출되고 스택에서 정수 값이 생성됩니다.

II IV MC pstack

인쇄물

2
4
600

4

스몰 토크 (Smalltalk / X) (87/101 자)

물론 우리는 파서의 토크 나이저를 쉽게 수정할 수 있지만 (클래스 라이브러리의 일부이고 수정을 위해 열려 있고 항상 존재하므로) 주어진 맥락에서 평가에만 영향을 미치므로 나머지는 시스템은 평소와 같이 작동합니다.

버전 1 :

평가 네임 스페이스에 여러 변수를 정의합니다. 따라서 이것은 대화 형 doIts (일명 회피)에 영향을 미칩니다.

(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.

따라서 기본적으로 언제든지 ( "InRomanScope 쿼리") false를 요청할 수 있습니다.

그런 다음 스캐너의 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


스몰 토크를 만나서 반갑습니다!

4

Haskell, 템플릿 Haskell로마 숫자 에서 메타 프로그래밍을 사용하는 Haskell :

{-# 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-네 상자의 편지. 숫자 배열을 사용하여 이러한 문자의 색인을 만들고 로마 숫자의 하위 단어를 만듭니다.
  • 841,3#79bc5yuukh -이것은 엄격하게 인코딩 된 숫자 데이터입니다. *
  • (_1,~3#.inv]) -삼항으로 확장하고 -1을 추가하여 위의 데이터를 해독합니다.
  • ('';&;:(...){' ',[)&.>-왼쪽에있는 숫자를 오른쪽에있는 상자 ( &.>) 와 짝을 이루어 숫자 배열을 해독 한 다음 문자를 사용하여 색인을 생성합니다. 문자 목록 앞에 공백 문자를 붙여서 0을 공백으로 취급합니다. 이 절차는 같은 단어의 목록 구축 I II III IV V VI VII VIII IXM MM MMM.
  • {-단어로 가득 찬이 네 상자의 카티 전 곱을 가져옵니다. 이제 모든 로마 숫자로 구성된 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

* 나중에 3 밑에서 읽을 수있는 숫자 2933774030998이 필요합니다. 30보다 크지 않은 숫자를 사용하여 79 밑으로 표현할 수 있습니다 .J는 최대 35 자릿수 만 이해할 수 있기 때문에 좋습니다 (0-9 az). 소수점 이하 3자를 저장합니다.


3

파이썬

아이디어는 다른 답변처럼 간단합니다. 그러나 깔끔하고 글로벌 네임 스페이스를 오염시키지 않기 위해 컨텍스트 관리자가 사용됩니다. 이것은 또한 당신이 사용하려는 로마 숫자의 범위를 미리 선언해야한다는 제한을 부과합니다.

참고 간단하게 유지하고 바퀴를 재발 명하지 않기 위해 로마 파이썬 패키지를 사용했습니다.

이행

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

파이썬

이것은 아마도 파이썬을 사용하는 가장 간단한 해결책 일 것입니다.

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의 컴파일 타임 함수 평가 사용

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∘ר 각각 한 번과 다섯 번

  10* 10의 힘

  ⍳4 0에서 3까지

0,⍨ 제로 추가

2(…)/ 각 길이 2 개의 슬라이딩 윈도우에서 다음 익명 함수 열차를 적용하십시오.

  ⊣× 왼쪽 논쟁 시간

  ¯1* 부정적인 힘의 힘

  < 왼쪽 인수가 오른쪽 인수보다 작은 지 여부

+/ 합집합

⍵'←', 인수 (로마 숫자)와 할당 화살표를 붙입니다.

 형식 (숫자를 평평하게하고 텍스트로 변환)

 그것을 실행하십시오 (익명 함수 외부에서 할당합니다)

온라인으로 사용해보십시오! (최대 길이 5 사용)


2

PHP

유효한 로마 숫자에 대한 몇 가지 규칙이 있습니다.

  1. 낮은 값보다 큰 값을 쓰십시오

  2. [I,X,C]다음 2 개 더 큰 값 앞에만 빼기

  3. [I,X,C]다음 2보다 큰 값보다 두 배 더하기

  4. [I,X,C]더 큰 값을 두 배로 빼기

  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 mar

@Daniero 이제 코드가 작동합니다
Jörg Hülsermann

아, 그건 낫다 :)
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 에서도이 작업을 수행하는 다른 방법 (그리고 아마도 더 나은 방법)이 있다고 확신합니다.

추신. 내 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 바이트

A는 어떤 입력을지지 않습니다 서브 루틴을 선언하고 실행할 때이 만들어 publicLY 접근 Enum, R로마 숫자의 값을 모두 포함한다. 이 값은 Enum을 참조하지 않고 직접 사용할 수 있습니다.

열거 형 값은 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.