Match Roman Numerals The 2019 Stack Overflow Developer Survey Results Are In Unicorn Meta Zoo #1: Why another podcast? Announcing the arrival of Valued Associate #679: Cesar Manara Sandbox for Proposed Challenges The PPCG Site design is on its way - help us make it awesome!Covering a Skyline with brush strokesSwap the EndiannessDetermine the “Luck” of a stringTips for golfing in 05AB1ECollapsing numbersQuine outputs itself in binaryMulti-level marketing “legs” investment ruleRoman numeral converter functionOptimal short-hand roman numeral generatorCount from 1 to 100… in Roman NumeralsCounting rods; count your rodsNumbers as Circular GraphicsAmbiguous Roman Numeral Magic SquaresConvert ciphered Roman numerals to Arabic decimalsInteger goes back and forth through timeLook-and-say sequence: roman numerals editionAm I a Self Number?When in Rome, Count as Romans do?
Huge performance difference of the command find with and without using %M option to show permissions
For what reasons would an animal species NOT cross a *horizontal* land bridge?
1960s short story making fun of James Bond-style spy fiction
Can a flute soloist sit?
Single author papers against my advisor's will?
University's motivation for having tenure-track positions
What is the role of 'For' here?
Make it rain characters
Word for: a synonym with a positive connotation?
Example of compact Riemannian manifold with only one geodesic.
How do you keep chess fun when your opponent constantly beats you?
Are there continuous functions who are the same in an interval but differ in at least one other point?
Is it ok to offer lower paid work as a trial period before negotiating for a full-time job?
Circular reasoning in L'Hopital's rule
What was the last x86 CPU that did not have the x87 floating-point unit built in?
What can I do if neighbor is blocking my solar panels intentionally?
How do spell lists change if the party levels up without taking a long rest?
How to read αἱμύλιος or when to aspirate
How did the audience guess the pentatonic scale in Bobby McFerrin's presentation?
Why not take a picture of a closer black hole?
Presidential Pardon
What do I do when my TA workload is more than expected?
60's-70's movie: home appliances revolting against the owners
Is this wall load bearing? Blueprints and photos attached
Match Roman Numerals
The 2019 Stack Overflow Developer Survey Results Are In
Unicorn Meta Zoo #1: Why another podcast?
Announcing the arrival of Valued Associate #679: Cesar Manara
Sandbox for Proposed Challenges
The PPCG Site design is on its way - help us make it awesome!Covering a Skyline with brush strokesSwap the EndiannessDetermine the “Luck” of a stringTips for golfing in 05AB1ECollapsing numbersQuine outputs itself in binaryMulti-level marketing “legs” investment ruleRoman numeral converter functionOptimal short-hand roman numeral generatorCount from 1 to 100… in Roman NumeralsCounting rods; count your rodsNumbers as Circular GraphicsAmbiguous Roman Numeral Magic SquaresConvert ciphered Roman numerals to Arabic decimalsInteger goes back and forth through timeLook-and-say sequence: roman numerals editionAm I a Self Number?When in Rome, Count as Romans do?
$begingroup$
Challenge
Given some input string, return a truthy value if it represents a correct roman numeral between 1 (=I
) and 3999 (=MMMCMXCIX
), and a falsey value otherwise.
Details
- The input is a non-empty string that only comprises the characters
IVXLCDM
. - The roman numerals (that we use here in this challenge) are defined as follows:
We use only following symbols:
Symbol I V X L C D M
Value 1 5 10 50 100 500 1000
To define which strings are actually valid roman numerals, it is probably easiest to provide the rule of conversation: To write a decimal number a3 a2 a1 a0
(where each ai
represents one digit. So for example to represent 792
we have a3=0, a2=7, a1=9, a0=2
.) as a roman numeral, we decompose it into the power of tens. The different powers of ten can be written as follows:
1-9: I, II, III, IV, V, VI, VII, VIII, IX
10-90: X, XX, XXX, XL, L, LX, LXX, LXXX, XC
100-900: C, CC, CCC, CD, D, DC, DCC, DCCC, CM
1000-3000: M, MM, MMM
Beginning at the left side with the most significant digit of the, we can convert the number that each digit represents separately and concatenate them. So for the example from above this would look like so:
Digit a3 a2 a1 a0
Decimal 0 7 9 2
Roman DCC XC II
Therefore the roman numeral for 792
is DCCXCII
. Here is a full list of all roman numerals that are relevant for this challenge: OEIS a006968.txt
Examples
Truthy
MCCXXXIV (1234)
CMLXXXVIII (988)
DXIV (514)
CI (101)
Falsey
MMIXVIII
IVX
IXV
MMMM
XXXVX
IVI
VIV
code-golf string number decision-problem roman-numerals
$endgroup$
add a comment |
$begingroup$
Challenge
Given some input string, return a truthy value if it represents a correct roman numeral between 1 (=I
) and 3999 (=MMMCMXCIX
), and a falsey value otherwise.
Details
- The input is a non-empty string that only comprises the characters
IVXLCDM
. - The roman numerals (that we use here in this challenge) are defined as follows:
We use only following symbols:
Symbol I V X L C D M
Value 1 5 10 50 100 500 1000
To define which strings are actually valid roman numerals, it is probably easiest to provide the rule of conversation: To write a decimal number a3 a2 a1 a0
(where each ai
represents one digit. So for example to represent 792
we have a3=0, a2=7, a1=9, a0=2
.) as a roman numeral, we decompose it into the power of tens. The different powers of ten can be written as follows:
1-9: I, II, III, IV, V, VI, VII, VIII, IX
10-90: X, XX, XXX, XL, L, LX, LXX, LXXX, XC
100-900: C, CC, CCC, CD, D, DC, DCC, DCCC, CM
1000-3000: M, MM, MMM
Beginning at the left side with the most significant digit of the, we can convert the number that each digit represents separately and concatenate them. So for the example from above this would look like so:
Digit a3 a2 a1 a0
Decimal 0 7 9 2
Roman DCC XC II
Therefore the roman numeral for 792
is DCCXCII
. Here is a full list of all roman numerals that are relevant for this challenge: OEIS a006968.txt
Examples
Truthy
MCCXXXIV (1234)
CMLXXXVIII (988)
DXIV (514)
CI (101)
Falsey
MMIXVIII
IVX
IXV
MMMM
XXXVX
IVI
VIV
code-golf string number decision-problem roman-numerals
$endgroup$
$begingroup$
Subset of this conversion challenge.
$endgroup$
– Shaggy
yesterday
$begingroup$
I still don't think this qualifies as a "subset" as the set of invalid inputs is larger. This challenge here only refers to the "well"-defined numbers that are used in OEIS A006968
$endgroup$
– flawr
yesterday
$begingroup$
Why isMMMM
invalid? Is there a letter for 5000 that should be used instead for M<letter>?
$endgroup$
– Skyler
15 hours ago
$begingroup$
Check out the specs, there is no such letter. The only symbols used areI,V,X,L,C,D,M
.
$endgroup$
– flawr
14 hours ago
add a comment |
$begingroup$
Challenge
Given some input string, return a truthy value if it represents a correct roman numeral between 1 (=I
) and 3999 (=MMMCMXCIX
), and a falsey value otherwise.
Details
- The input is a non-empty string that only comprises the characters
IVXLCDM
. - The roman numerals (that we use here in this challenge) are defined as follows:
We use only following symbols:
Symbol I V X L C D M
Value 1 5 10 50 100 500 1000
To define which strings are actually valid roman numerals, it is probably easiest to provide the rule of conversation: To write a decimal number a3 a2 a1 a0
(where each ai
represents one digit. So for example to represent 792
we have a3=0, a2=7, a1=9, a0=2
.) as a roman numeral, we decompose it into the power of tens. The different powers of ten can be written as follows:
1-9: I, II, III, IV, V, VI, VII, VIII, IX
10-90: X, XX, XXX, XL, L, LX, LXX, LXXX, XC
100-900: C, CC, CCC, CD, D, DC, DCC, DCCC, CM
1000-3000: M, MM, MMM
Beginning at the left side with the most significant digit of the, we can convert the number that each digit represents separately and concatenate them. So for the example from above this would look like so:
Digit a3 a2 a1 a0
Decimal 0 7 9 2
Roman DCC XC II
Therefore the roman numeral for 792
is DCCXCII
. Here is a full list of all roman numerals that are relevant for this challenge: OEIS a006968.txt
Examples
Truthy
MCCXXXIV (1234)
CMLXXXVIII (988)
DXIV (514)
CI (101)
Falsey
MMIXVIII
IVX
IXV
MMMM
XXXVX
IVI
VIV
code-golf string number decision-problem roman-numerals
$endgroup$
Challenge
Given some input string, return a truthy value if it represents a correct roman numeral between 1 (=I
) and 3999 (=MMMCMXCIX
), and a falsey value otherwise.
Details
- The input is a non-empty string that only comprises the characters
IVXLCDM
. - The roman numerals (that we use here in this challenge) are defined as follows:
We use only following symbols:
Symbol I V X L C D M
Value 1 5 10 50 100 500 1000
To define which strings are actually valid roman numerals, it is probably easiest to provide the rule of conversation: To write a decimal number a3 a2 a1 a0
(where each ai
represents one digit. So for example to represent 792
we have a3=0, a2=7, a1=9, a0=2
.) as a roman numeral, we decompose it into the power of tens. The different powers of ten can be written as follows:
1-9: I, II, III, IV, V, VI, VII, VIII, IX
10-90: X, XX, XXX, XL, L, LX, LXX, LXXX, XC
100-900: C, CC, CCC, CD, D, DC, DCC, DCCC, CM
1000-3000: M, MM, MMM
Beginning at the left side with the most significant digit of the, we can convert the number that each digit represents separately and concatenate them. So for the example from above this would look like so:
Digit a3 a2 a1 a0
Decimal 0 7 9 2
Roman DCC XC II
Therefore the roman numeral for 792
is DCCXCII
. Here is a full list of all roman numerals that are relevant for this challenge: OEIS a006968.txt
Examples
Truthy
MCCXXXIV (1234)
CMLXXXVIII (988)
DXIV (514)
CI (101)
Falsey
MMIXVIII
IVX
IXV
MMMM
XXXVX
IVI
VIV
code-golf string number decision-problem roman-numerals
code-golf string number decision-problem roman-numerals
edited 21 hours ago
flawr
asked yesterday
flawrflawr
27.1k667190
27.1k667190
$begingroup$
Subset of this conversion challenge.
$endgroup$
– Shaggy
yesterday
$begingroup$
I still don't think this qualifies as a "subset" as the set of invalid inputs is larger. This challenge here only refers to the "well"-defined numbers that are used in OEIS A006968
$endgroup$
– flawr
yesterday
$begingroup$
Why isMMMM
invalid? Is there a letter for 5000 that should be used instead for M<letter>?
$endgroup$
– Skyler
15 hours ago
$begingroup$
Check out the specs, there is no such letter. The only symbols used areI,V,X,L,C,D,M
.
$endgroup$
– flawr
14 hours ago
add a comment |
$begingroup$
Subset of this conversion challenge.
$endgroup$
– Shaggy
yesterday
$begingroup$
I still don't think this qualifies as a "subset" as the set of invalid inputs is larger. This challenge here only refers to the "well"-defined numbers that are used in OEIS A006968
$endgroup$
– flawr
yesterday
$begingroup$
Why isMMMM
invalid? Is there a letter for 5000 that should be used instead for M<letter>?
$endgroup$
– Skyler
15 hours ago
$begingroup$
Check out the specs, there is no such letter. The only symbols used areI,V,X,L,C,D,M
.
$endgroup$
– flawr
14 hours ago
$begingroup$
Subset of this conversion challenge.
$endgroup$
– Shaggy
yesterday
$begingroup$
Subset of this conversion challenge.
$endgroup$
– Shaggy
yesterday
$begingroup$
I still don't think this qualifies as a "subset" as the set of invalid inputs is larger. This challenge here only refers to the "well"-defined numbers that are used in OEIS A006968
$endgroup$
– flawr
yesterday
$begingroup$
I still don't think this qualifies as a "subset" as the set of invalid inputs is larger. This challenge here only refers to the "well"-defined numbers that are used in OEIS A006968
$endgroup$
– flawr
yesterday
$begingroup$
Why is
MMMM
invalid? Is there a letter for 5000 that should be used instead for M<letter>?$endgroup$
– Skyler
15 hours ago
$begingroup$
Why is
MMMM
invalid? Is there a letter for 5000 that should be used instead for M<letter>?$endgroup$
– Skyler
15 hours ago
$begingroup$
Check out the specs, there is no such letter. The only symbols used are
I,V,X,L,C,D,M
.$endgroup$
– flawr
14 hours ago
$begingroup$
Check out the specs, there is no such letter. The only symbols used are
I,V,X,L,C,D,M
.$endgroup$
– flawr
14 hours ago
add a comment |
15 Answers
15
active
oldest
votes
$begingroup$
Verbose, 1362 bytes
GET A ROMAN NUMERAL TYPED IN BY THE CURRENT PERSON USING THIS PROGRAM AND PUT IT ONTO THE TOP OF THE PROGRAM STACK
PUT THE NUMBER MMMM ONTO THE TOP OF THE PROGRAM STACK
MOVE THE FIRST ELEMENT OF THE PROGRAM STACK TO THE SECOND ELEMENT'S PLACE AND THE SECOND ELEMENT OF THE STACK TO THE FIRST ELEMENT'S PLACE
DIVIDE THE FIRST ELEMENT OF THE PROGRAM STACK BY THE SECOND ELEMENT OF THE PROGRAM STACK AND PUT THE RESULT ONTO THE TOP OF THE PROGRAM STACK
PUT THE NUMBER V ONTO THE TOP OF THE PROGRAM STACK
GET THE FIRST ELEMENT OF THE PROGRAM STACK AND THE SECOND ELEMENT OF THE PROGRAM STACK AND IF THE SECOND ELEMENT OF THE PROGRAM STACK IS NOT ZERO JUMP TO THE INSTRUCTION THAT IS THE CURRENT INSTRUCTION NUMBER AND THE FIRST ELEMENT ADDED TOGETHER'S RESULT
PUT THE NUMBER I ONTO THE TOP OF THE PROGRAM STACK
GET THE TOP ELEMENT OF THE STACK AND OUTPUT IT FOR THE CURRENT PERSON USING THIS PROGRAM TO SEE
PUT THE NUMBER III ONTO THE TOP OF THE PROGRAM STACK
GET THE FIRST ELEMENT OF THE PROGRAM STACK AND THE SECOND ELEMENT OF THE PROGRAM STACK AND IF THE SECOND ELEMENT OF THE PROGRAM STACK IS NOT ZERO JUMP TO THE INSTRUCTION THAT IS THE CURRENT INSTRUCTION NUMBER AND THE FIRST ELEMENT ADDED TOGETHER'S RESULT
PUT THE NUMBER NULLA ONTO THE TOP OF THE PROGRAM STACK
GET THE TOP ELEMENT OF THE STACK AND OUTPUT IT FOR THE CURRENT PERSON USING THIS PROGRAM TO SEE
Outputs I
for valid roman numerals in the range I-MMMCMXCIX
and NULLA
(0) or informs user input is not a valid roman numeral otherwise.
$endgroup$
10
$begingroup$
I can't decide if this is the right tool for the job or not.
$endgroup$
– Vaelus
yesterday
4
$begingroup$
Is this the right tool for any job?
$endgroup$
– omzrs
yesterday
add a comment |
$begingroup$
C# (Visual C# Interactive Compiler), 79 109 bytes
This seems like a Regex challenge, I'm sure a shorter solution can be found...
s=>System.Text.RegularExpressions.Regex.IsMatch(s,"^M0,3(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)$")
Try it online!
$endgroup$
$begingroup$
Couldn't you shorten0,3
to,3
?
$endgroup$
– flawr
yesterday
$begingroup$
@flawr doesn't seem to capture anything then
$endgroup$
– Innat3
yesterday
1
$begingroup$
Ah sorry, only things like5,
work, but not,5
.
$endgroup$
– flawr
yesterday
2
$begingroup$
You can add it as compiler flag instead, so it's 72 bytes and the language should be changed to C# (Visual C# Interactive Compiler) with flag/u:System.Text.RegularExpressions.Regex
, like this answer :)
$endgroup$
– Kevin Cruijssen
yesterday
3
$begingroup$
Alternate regex:^M?M?M?(C[MD]|D?C?C?C?)(X[CL]|L?X?X?X?)(I[XV]|V?I?I?I?)$
. Same length, but looks weirder (which is the goal, right?)
$endgroup$
– Embodiment of Ignorance
yesterday
|
show 6 more comments
$begingroup$
Java 8, 70 bytes
s->s.matches("M0,3(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)")
Port of @Innat3's C# answer, so make sure to upvote him!
Try it online.
Explanation:
s-> // Method with String parameter and boolean return-type
s.matches("...") // Check if the string matches the regex fully
// (which implicitly adds a leading "^" and trailing "$")
M0,3 // No, 1, 2, or 3 adjacent "M"
( | ) // Followed by either:
C[MD] // A "C" with an "M" or "D" after it
| // or:
D? // An optional "D"
C0,3 // Followed by no, 1, 2, or 3 adjacent "C"
( | ) // Followed by either:
X[CL] // An "X" with a "C" or "L" after it
| // or:
L? // An optional "L"
X0,3 // Followed by no, 1, 2, or 3 adjacent "X"
( | ) // Followed by either:
I[XV] // An "I" with an "X" or "V" after it
| // or:
V? // An optional "V"
I0,3 // Followed by no, 1, 2, or 3 adjacent "I"
$endgroup$
add a comment |
$begingroup$
Wolfram Language (Mathematica), 35 bytes
Check[FromRomanNumeral@#<3999,1<0]&
Try it online!
5 bytes saved, thanks to @attinat
the limitation [1,3999]
unfortunateley costs 7 bytes...
here is the code for any roman number
Wolfram Language (Mathematica), 28 bytes
Check[FromRomanNumeral@#,F]&
Try it online!
the above code works for any number, not just [1,3999]
$endgroup$
2
$begingroup$
@ExpiredData "The input is a non-empty string that only comprises the charactersIVXLCDM
."
$endgroup$
– mathmandan
yesterday
$begingroup$
35 bytes.Boole
is also shorter (by one byte) than usingIf
in that way.
$endgroup$
– attinat
yesterday
add a comment |
$begingroup$
CP-1610 assembly (Intellivision), 52 ... 48 47 DECLEs1 = 59 bytes
Let's try this on a system that predates Perl by a good 7 years. :-)
Takes a pointer to a null-terminated string in R4. Sets the Zero flag if the input is a valid Roman numeral, or clears it otherwise.
ROMW 10 ; use 10-bit ROM width
ORG $4800 ; map this program at $4800
;; ------------------------------------------------------------- ;;
;; test code ;;
;; ------------------------------------------------------------- ;;
4800 EIS ; enable interrupts
4801 SDBD ; R5 = pointer into test case index
4802 MVII #ndx, R5
4805 MVII #$214, R3 ; R3 = backtab pointer
4807 MVII #11, R0 ; R0 = number of test cases
4809 loop SDBD ; R4 = pointer to next test case
480A MVI@ R5, R4
480B PSHR R0 ; save R0, R3, R5 onto the stack
480C PSHR R3
480D PSHR R5
480E CALL isRoman ; invoke our routine
4811 PULR R5 ; restore R5 and R3
4812 PULR R3
4813 MVII #$1A7, R0 ; use a white 'T' by default
4815 BEQ disp
4817 MVII #$137, R0 ; or a white 'F' is the Z flag was cleared
4819 disp MVO@ R0, R3 ; draw it
481A INCR R3 ; increment the backtab pointer
481B PULR R0 ; restore R0
481C DECR R0 ; and advance to the next test case, if any
481D BNEQ loop
481F DECR R7 ; loop forever
;; ------------------------------------------------------------- ;;
;; test cases ;;
;; ------------------------------------------------------------- ;;
4820 ndx BIDECLE test0, test1, test2, test3
4828 BIDECLE test4, test5, test6, test7, test8, test9, test10
; truthy
4836 test0 STRING "MCCXXXIV", 0
483F test1 STRING "CMLXXXVIII", 0
484A test2 STRING "DXIV", 0
484F test3 STRING "CI", 0
; falsy
4852 test4 STRING "MMIXVIII", 0
485B test5 STRING "IVX", 0
485F test6 STRING "IXV", 0
4863 test7 STRING "MMMM", 0
4868 test8 STRING "XXXVX", 0
486E test9 STRING "IVI", 0
4872 test10 STRING "VIV", 0
;; ------------------------------------------------------------- ;;
;; routine ;;
;; ------------------------------------------------------------- ;;
isRoman PROC
4876 PSHR R5 ; push the return address
4877 MOVR R7, R2 ; R2 = dummy 1st suffix
4878 MOVR R2, R5 ; R5 = pointer into table
4879 ADDI #@tbl-$+1,R5
487B @loop MVI@ R5, R1 ; R1 = main digit (M, C, X, I)
487C MVI@ R5, R3 ; R3 = prefix or 2nd suffix (-, D, L, V)
487D MVI@ R4, R0 ; R0 = next digit
487E CMPR R0, R3 ; if this is the prefix ...
487F BNEQ @main
4881 COMR R2 ; ... disable the suffixes
4882 COMR R3 ; by setting them to invalid values
4883 MVI@ R4, R0 ; and read R0 again
4884 @main CMPR R0, R1 ; if R0 is not equal to the main digit,
4885 BNEQ @back ; assume that this part is over
4887 MVI@ R4, R0 ; R0 = next digit
4888 CMPR R0, R1 ; if this is a 2nd occurrence
4889 BNEQ @suffix ; of the main digit ...
488B CMP@ R4, R1 ; ... it may be followed by a 3rd occurrence
488C BNEQ @back
488E MOVR R2, R0 ; if so, force the test below to succeed
488F @suffix CMPR R0, R2 ; otherwise, it may be either the 1st suffix
4890 BEQ @next
4892 CMPR R0, R3 ; or the 2nd suffix (these tests always fail
4893 BEQ @next ; if the suffixes were disabled above)
4895 @back DECR R4 ; the last digit either belongs to the next
; iteration or is invalid
4896 @next MOVR R1, R2 ; use the current main digit
; as the next 1st suffix
4897 SUBI #'I', R1 ; was it the last iteration? ...
4899 BNEQ @loop
489B CMP@ R4, R1 ; ... yes: make sure that we've also reached
; the end of the input
489C PULR R7 ; return
489D @tbl DECLE 'M', '-' ; table format: main digit, 2nd suffix
489F DECLE 'C', 'D'
48A1 DECLE 'X', 'L'
48A3 DECLE 'I', 'V'
ENDP
How?
The regular expression can be rewritten as 4 groups with the same structure, provided that #
is any invalid character that is guaranteed not be present in the input string.
+-------+---> main digit
| |
(M[##]|#?M0,3)(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)
|| |
|+--+-----> prefix or second suffix
|
+---------> first suffix
The first suffix of the group $N$ is the main digit of the group $N-1$. Therefore, we can store the patterns with the pair $(textmain_digit, textsecond_suffix)$ alone.
Our routine attempts to parse the input string character by character according to these patterns and eventually checks whether the end of the string is reached.
Output
screenshot of jzIntv
1. A CP-1610 opcode is encoded with a 10-bit value, known as a 'DECLE'. This routine is 47 DECLEs long, starting at $4876 and ending at $48A4 (included).
$endgroup$
$begingroup$
wouldn't this be one of the few places where fractional bytes are valid
$endgroup$
– ASCII-only
22 hours ago
$begingroup$
@ASCII-only I used to think so, but I don't know for sure. See the comments of this answer for some insight about this.
$endgroup$
– Arnauld
22 hours ago
$begingroup$
@ASCII-only Also, I've just found this post in meta that tends to confirm it's probably best to round to whole bytes.
$endgroup$
– Arnauld
21 hours ago
$begingroup$
ah, so it's only 10 bits when it's in RAM?
$endgroup$
– ASCII-only
21 hours ago
$begingroup$
The program is never stored in RAM, only in ROM. So it depends on the memory chips used in the cartridge. The CPU is designed to access either 10-bit or 16-bit ROM. The "ROMW 10" directive forces the compiler to generate code in 10-bit format.
$endgroup$
– Arnauld
21 hours ago
add a comment |
$begingroup$
R, 74 71 56 bytes
Thanks to @RobinRyder, @Giuseppe, & @MickyT for their suggestions how to use grep effectively with R's built in as.roman
.
sub("^M(.+)","\1",scan(,""))%in%paste(as.roman(1:2999))
Try it online!
$endgroup$
$begingroup$
as.roman
won't work anyway, since it only works up to3899
for some reason.
$endgroup$
– Giuseppe
yesterday
$begingroup$
I really should read the documentation better, Probably because 4000 doesn't have a definite representation in Roman, so how'd one do 3900. This is similar to 390 and now I just found an issue with my grep where I'd have to anchor the pattern.
$endgroup$
– CT Hall
yesterday
$begingroup$
@Giuseppe, addressed, using the same regex as the other answers.
$endgroup$
– CT Hall
yesterday
$begingroup$
I wonder if there's a way to use.romans
here...probably not.
$endgroup$
– Giuseppe
yesterday
2
$begingroup$
66 bytes usingas.roman
: first strip the initialM
if there is one, then check whether the result is inas.roman(1:2999)
. This requires special handling of the case where the input isM
.
$endgroup$
– Robin Ryder
yesterday
|
show 10 more comments
$begingroup$
Wolfram Language (Mathematica), 32 bytes
RomanNumeral@Range@3999~Count~#&
Try it online!
$endgroup$
add a comment |
$begingroup$
Jelly, 48 47 46 bytes
-1 thanks to Nick Kennedy
5Żo7;“ÆæC‘b3ð“IVXLCDM”ị@3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ
A monadic Link accepting a non-empty list of characters consisting only of IVXLCDM
which yields either 1
(when it's a valid Roman numeral between $1$ and $3999$) or 0
(if not).
Try it online! Or see the test-suite.
How?
Needs updating...
7R;“¿ç‘ḃ2ŒQ€6¦ị - Link 1, acceptable "digits": list of characters e.g. "IVX"
7R - range of seven [1,2,3,4,5,6,7]
“¿ç‘ - list of code-page indices [11,23]
; - concatenate [1,2,3,4,5,6,7,11,23]
ḃ2 - to bijective base two [[1],[2],[1,1],[1,2],[2,1],[2,2],[1,1,1],[2,1,1],[2,1,1,1]]
¦ - sparse application...
6 - ...to indices: six
ŒQ€ - ...do: for €ach: distinct sieve ...,[1,0],...
ị - index into input ["I","V","II", "IV", "VI", "IX", "III", "VII", "VIII" ]
“IVXLCDM”Ç3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ - Main Link: list of characters
“IVXLCDM” - list of characters
3Ƥ - for infixes of length three: ("IVX","VXL","XLC","LCD","CDM")
Ç - call the last Link (1) as a monad
m2 - modulo two slice (results for "IVX", "XLC", and "CDM" only)
¤ - nilad followed by link(s) as a nilad:
”M - character 'M'
Ɱ3 - map across [1,2,3] with:
ẋ - repeat -> ["M", "MM", "MMM"]
ṭ - tack
Ż€ - prepend a zero to each
Ṛ - reverse
- -- now we have the table:
- 0 M MM MMM
- 0 C D CC CD DC CM CCC DCC DCCC
- 0 X L XX XL LX XC XXX LXX LXXX
- 0 I V II IV VI IX III VII VIII
Œp - Cartesian product -> [[0,0,0,0],[0,0,0,"I"],...,["M","CM",0,"IV"],...]
F€ - flatten €ach -> [[0,0,0,0],[0,0,0,'I'],...,['M','C','M',0,'I','V'],...]
ḟ€0 - filter out the zeros from €ach -> ["","I",...,"MCMIV",...]
ċ - count occurrences of the input
$endgroup$
$begingroup$
There seems to be a redundant space on the first line. Another byte. Another byte can be saved by using a simpler first line. Try it online!
$endgroup$
– Nick Kennedy
23 hours ago
$begingroup$
Thanks, I've saved one more from it.
$endgroup$
– Jonathan Allan
21 hours ago
add a comment |
$begingroup$
Perl 5 (-p
), 57 bytes
$_=/^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$/&!/(.)13/
TIO
- uses almost the same regular expression except
0,3
quantifier was changed by*
&!/(.)13/
to ensure the same character can't occur 4 times in a row.- can't be golfed with
-/(.)13/
because would give-1
forIIIIVI
for example
$endgroup$
add a comment |
$begingroup$
Python 2, 81 bytes
import re
re.compile('M,3(D?C,3|C[DM])(L?X,3|X[LC])(V?I,3|I[VX])$').match
Try it online!
Let's look at the last part of the regex, which matching the Roman numerals up to 9 (including the empty string)
V?I,3|I[VX]
This has two alternatives separated by |
:
V?I,3
: An optionalV
followed by up to 3I
's. This matches the empty stringI
,II
,III
,V
,VI
,VII
,VIII
.I[VX]
: AnI
followed by aV
orX
. This matchesIV
andIX
.
The same things with X,L,C
matching the tens, with C,D,M
matches the hundreds, and finally ^M,3
allows up to 3 M
's (thousands) at the start.
I tried generating the template for each trio of characters rather than writing it 3 times, but this was a lot longer.
$endgroup$
$begingroup$
No need for the^
anchor at the beginning;match
already implies it matches at the beginning of the string.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger Thanks, I removed the^
.
$endgroup$
– xnor
yesterday
$begingroup$
Although I think you messed up the count in the edit; should be 83, not 81.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger The count is 81 because thef=
isn't included in the code since anonynomous functions are allowed. It's just for TIO.
$endgroup$
– xnor
yesterday
1
$begingroup$
Ah, makes sense. Annoying there's no way to organize it to hide that in the header or footer, but yeah, unassignedlambda
s are legal, so unassigned bound methods of compiled regex should be good too.
$endgroup$
– ShadowRanger
yesterday
|
show 1 more comment
$begingroup$
Retina, 56 51 bytes
(.)13
0
^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$
Port of @NahuelFouilleul's Perl 5 answer, so make sure to upvote him!
Try it online or verify all test cases.
Explanation:
(.)13 # If four adjacent characters can be found which are the same
0 # Replace it with a 0
^...$ # Then check if the string matches the following fully:
M* # No or any amount of adjacent "M"
( | ) # Followed by either:
C[MD] # A "C" with an "M" or "D" after it
| # or:
D? # An optional "D"
C* # Followed by no or any amount of adjacent "C"
( | ) # Followed by either:
X[CL] # An "X" with a "C" or "L" after it
| # or:
L? # An optional "L"
X* # Followed by no or any amount of adjacent "X"
( | ) # Followed by either:
I[XV] # An "I" with an "X" or "V" after it
| # or:
V? # An optional "V"
I* # Followed by no or any amount of adjacent "I"
$endgroup$
add a comment |
$begingroup$
05AB1E, 61 bytes
•1∞Γ'иÛnuÞ₂…•Ž8вв€SÐ)v.•6#&‘нδ•u3ôNèyè}'M3L×)Rεõš}`3Fâ}€˜JIå
Try it online or verify all test cases.
Explanation:
•1∞Γ'иÛnuÞ₂…• '# Push compressed integer 397940501547566186191992778
Ž8в # Push compressed integer 2112
в # Convert the integer to Base-2112 as list:
# [1,11,111,12,2,21,211,2111,10]
€S # Convert each number to a list of digits
Ð # Triplicate this list
) # And wrap it into a list of lists (of lists)
v # Loop `y` over each these three lists:
.•6#&‘нδ• # Push compressed string "xivcxlmcd"
u # Uppercased
3ô # And split into parts of size 3: ["XIV","CXL","MCD"]
Nè # Use the loop index to get the current part
yè # And index the list of lists of digits into this string
}'M '# After the loop: push "M"
3L # Push list [1,2,3]
× # Repeat the "M" that many times: ["M","MM","MMM"]
) # Wrap all lists on the stack into a list:
# [[["I"],["I","I"],["I","I","I"],["I","V"],["V"],["V","I"],["V","I","I"],["V","I","I","I"],["I","X"]],[["X"],["X","X"],["X","X","X"],["X","L"],["L"],["L","X"],["L","X","X"],["L","X","X","X"],["X","C"]],[["C"],["C","C"],["C","C","C"],["C","D"],["D"],["D","C"],["D","C","C"],["D","C","C","C"],["C","M"]],["M","MM","MMM"]]
R # Reverse this list
εõš} # Prepend an empty string "" before each inner list
` # Push the four lists onto the stack
3F # Loop 3 times:
â # Take the cartesian product of the two top lists
}€˜ # After the loop: flatten each inner list
J # Join each inner list together to a single string
Iå # And check if the input is in this list
# (after which the result is output implicitly)
See this 05AB1E tip of mine (sections How to compress strings not part of the dictionary?, How to compress large integers?, and How to compress integer lists?) to understand why:
•1∞Γ'иÛnuÞ₂…•
is397940501547566186191992778
Ž8в
is2112
•1∞Γ'иÛnuÞ₂…•Ž8вв
is[1,11,111,12,2,21,211,2111,10]
.•6#&‘нδ•
is"xivcxlmcd"
$endgroup$
add a comment |
$begingroup$
perl -MRegexp::Common -pe, 34 bytes
$_=/^$REnumroman$/&!/(.)13/
The &!/(.)13/
part is necessary, because Regexp::Common
allows four (but not five) of the same characters in a row. That way, it matches roman numbers used on clock faces, where IIII
is often used for 4.
$endgroup$
add a comment |
$begingroup$
Python 3, 116 113 109 107 105 106 bytes
import re
lambda n:re.match(r'(M,3(C(M|CC?|D)?|DC,3))(X(C|XX?|L)?|(LX,3))?(I(X|II?|V)?|VI,3)?$',n)
Try it online!
-1 byte thanks to ShadowRanger
$endgroup$
2
$begingroup$
As I mentioned on the Py2 answer, the leading^
is unnecessary sincematch
only matches at the beginning of a string already.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger added anchors while debugging and then didn't try again without them. I'll remember that now - thanks! :)
$endgroup$
– Noodle9
16 hours ago
$begingroup$
Well, just to be clear, the trailing$
is necessary (onlyfullmatch
implies anchors on both ends, and obviously that would cost more than a$
).
$endgroup$
– ShadowRanger
15 hours ago
$begingroup$
@ShadowRanger Ah! That explains why I needed anchors! Didn't realize I only needed to anchor the end. Thanks again.
$endgroup$
– Noodle9
15 hours ago
add a comment |
$begingroup$
Ruby, (-n
) 56 bytes
p~/^M,3(D?C,3|CM|CD)(L?X,3|XC|XL)(V?I,3|IV|IX)$/
Try it online!
Outputs 0 (truthy) or nil (falsy).
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "200"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodegolf.stackexchange.com%2fquestions%2f183014%2fmatch-roman-numerals%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
15 Answers
15
active
oldest
votes
15 Answers
15
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Verbose, 1362 bytes
GET A ROMAN NUMERAL TYPED IN BY THE CURRENT PERSON USING THIS PROGRAM AND PUT IT ONTO THE TOP OF THE PROGRAM STACK
PUT THE NUMBER MMMM ONTO THE TOP OF THE PROGRAM STACK
MOVE THE FIRST ELEMENT OF THE PROGRAM STACK TO THE SECOND ELEMENT'S PLACE AND THE SECOND ELEMENT OF THE STACK TO THE FIRST ELEMENT'S PLACE
DIVIDE THE FIRST ELEMENT OF THE PROGRAM STACK BY THE SECOND ELEMENT OF THE PROGRAM STACK AND PUT THE RESULT ONTO THE TOP OF THE PROGRAM STACK
PUT THE NUMBER V ONTO THE TOP OF THE PROGRAM STACK
GET THE FIRST ELEMENT OF THE PROGRAM STACK AND THE SECOND ELEMENT OF THE PROGRAM STACK AND IF THE SECOND ELEMENT OF THE PROGRAM STACK IS NOT ZERO JUMP TO THE INSTRUCTION THAT IS THE CURRENT INSTRUCTION NUMBER AND THE FIRST ELEMENT ADDED TOGETHER'S RESULT
PUT THE NUMBER I ONTO THE TOP OF THE PROGRAM STACK
GET THE TOP ELEMENT OF THE STACK AND OUTPUT IT FOR THE CURRENT PERSON USING THIS PROGRAM TO SEE
PUT THE NUMBER III ONTO THE TOP OF THE PROGRAM STACK
GET THE FIRST ELEMENT OF THE PROGRAM STACK AND THE SECOND ELEMENT OF THE PROGRAM STACK AND IF THE SECOND ELEMENT OF THE PROGRAM STACK IS NOT ZERO JUMP TO THE INSTRUCTION THAT IS THE CURRENT INSTRUCTION NUMBER AND THE FIRST ELEMENT ADDED TOGETHER'S RESULT
PUT THE NUMBER NULLA ONTO THE TOP OF THE PROGRAM STACK
GET THE TOP ELEMENT OF THE STACK AND OUTPUT IT FOR THE CURRENT PERSON USING THIS PROGRAM TO SEE
Outputs I
for valid roman numerals in the range I-MMMCMXCIX
and NULLA
(0) or informs user input is not a valid roman numeral otherwise.
$endgroup$
10
$begingroup$
I can't decide if this is the right tool for the job or not.
$endgroup$
– Vaelus
yesterday
4
$begingroup$
Is this the right tool for any job?
$endgroup$
– omzrs
yesterday
add a comment |
$begingroup$
Verbose, 1362 bytes
GET A ROMAN NUMERAL TYPED IN BY THE CURRENT PERSON USING THIS PROGRAM AND PUT IT ONTO THE TOP OF THE PROGRAM STACK
PUT THE NUMBER MMMM ONTO THE TOP OF THE PROGRAM STACK
MOVE THE FIRST ELEMENT OF THE PROGRAM STACK TO THE SECOND ELEMENT'S PLACE AND THE SECOND ELEMENT OF THE STACK TO THE FIRST ELEMENT'S PLACE
DIVIDE THE FIRST ELEMENT OF THE PROGRAM STACK BY THE SECOND ELEMENT OF THE PROGRAM STACK AND PUT THE RESULT ONTO THE TOP OF THE PROGRAM STACK
PUT THE NUMBER V ONTO THE TOP OF THE PROGRAM STACK
GET THE FIRST ELEMENT OF THE PROGRAM STACK AND THE SECOND ELEMENT OF THE PROGRAM STACK AND IF THE SECOND ELEMENT OF THE PROGRAM STACK IS NOT ZERO JUMP TO THE INSTRUCTION THAT IS THE CURRENT INSTRUCTION NUMBER AND THE FIRST ELEMENT ADDED TOGETHER'S RESULT
PUT THE NUMBER I ONTO THE TOP OF THE PROGRAM STACK
GET THE TOP ELEMENT OF THE STACK AND OUTPUT IT FOR THE CURRENT PERSON USING THIS PROGRAM TO SEE
PUT THE NUMBER III ONTO THE TOP OF THE PROGRAM STACK
GET THE FIRST ELEMENT OF THE PROGRAM STACK AND THE SECOND ELEMENT OF THE PROGRAM STACK AND IF THE SECOND ELEMENT OF THE PROGRAM STACK IS NOT ZERO JUMP TO THE INSTRUCTION THAT IS THE CURRENT INSTRUCTION NUMBER AND THE FIRST ELEMENT ADDED TOGETHER'S RESULT
PUT THE NUMBER NULLA ONTO THE TOP OF THE PROGRAM STACK
GET THE TOP ELEMENT OF THE STACK AND OUTPUT IT FOR THE CURRENT PERSON USING THIS PROGRAM TO SEE
Outputs I
for valid roman numerals in the range I-MMMCMXCIX
and NULLA
(0) or informs user input is not a valid roman numeral otherwise.
$endgroup$
10
$begingroup$
I can't decide if this is the right tool for the job or not.
$endgroup$
– Vaelus
yesterday
4
$begingroup$
Is this the right tool for any job?
$endgroup$
– omzrs
yesterday
add a comment |
$begingroup$
Verbose, 1362 bytes
GET A ROMAN NUMERAL TYPED IN BY THE CURRENT PERSON USING THIS PROGRAM AND PUT IT ONTO THE TOP OF THE PROGRAM STACK
PUT THE NUMBER MMMM ONTO THE TOP OF THE PROGRAM STACK
MOVE THE FIRST ELEMENT OF THE PROGRAM STACK TO THE SECOND ELEMENT'S PLACE AND THE SECOND ELEMENT OF THE STACK TO THE FIRST ELEMENT'S PLACE
DIVIDE THE FIRST ELEMENT OF THE PROGRAM STACK BY THE SECOND ELEMENT OF THE PROGRAM STACK AND PUT THE RESULT ONTO THE TOP OF THE PROGRAM STACK
PUT THE NUMBER V ONTO THE TOP OF THE PROGRAM STACK
GET THE FIRST ELEMENT OF THE PROGRAM STACK AND THE SECOND ELEMENT OF THE PROGRAM STACK AND IF THE SECOND ELEMENT OF THE PROGRAM STACK IS NOT ZERO JUMP TO THE INSTRUCTION THAT IS THE CURRENT INSTRUCTION NUMBER AND THE FIRST ELEMENT ADDED TOGETHER'S RESULT
PUT THE NUMBER I ONTO THE TOP OF THE PROGRAM STACK
GET THE TOP ELEMENT OF THE STACK AND OUTPUT IT FOR THE CURRENT PERSON USING THIS PROGRAM TO SEE
PUT THE NUMBER III ONTO THE TOP OF THE PROGRAM STACK
GET THE FIRST ELEMENT OF THE PROGRAM STACK AND THE SECOND ELEMENT OF THE PROGRAM STACK AND IF THE SECOND ELEMENT OF THE PROGRAM STACK IS NOT ZERO JUMP TO THE INSTRUCTION THAT IS THE CURRENT INSTRUCTION NUMBER AND THE FIRST ELEMENT ADDED TOGETHER'S RESULT
PUT THE NUMBER NULLA ONTO THE TOP OF THE PROGRAM STACK
GET THE TOP ELEMENT OF THE STACK AND OUTPUT IT FOR THE CURRENT PERSON USING THIS PROGRAM TO SEE
Outputs I
for valid roman numerals in the range I-MMMCMXCIX
and NULLA
(0) or informs user input is not a valid roman numeral otherwise.
$endgroup$
Verbose, 1362 bytes
GET A ROMAN NUMERAL TYPED IN BY THE CURRENT PERSON USING THIS PROGRAM AND PUT IT ONTO THE TOP OF THE PROGRAM STACK
PUT THE NUMBER MMMM ONTO THE TOP OF THE PROGRAM STACK
MOVE THE FIRST ELEMENT OF THE PROGRAM STACK TO THE SECOND ELEMENT'S PLACE AND THE SECOND ELEMENT OF THE STACK TO THE FIRST ELEMENT'S PLACE
DIVIDE THE FIRST ELEMENT OF THE PROGRAM STACK BY THE SECOND ELEMENT OF THE PROGRAM STACK AND PUT THE RESULT ONTO THE TOP OF THE PROGRAM STACK
PUT THE NUMBER V ONTO THE TOP OF THE PROGRAM STACK
GET THE FIRST ELEMENT OF THE PROGRAM STACK AND THE SECOND ELEMENT OF THE PROGRAM STACK AND IF THE SECOND ELEMENT OF THE PROGRAM STACK IS NOT ZERO JUMP TO THE INSTRUCTION THAT IS THE CURRENT INSTRUCTION NUMBER AND THE FIRST ELEMENT ADDED TOGETHER'S RESULT
PUT THE NUMBER I ONTO THE TOP OF THE PROGRAM STACK
GET THE TOP ELEMENT OF THE STACK AND OUTPUT IT FOR THE CURRENT PERSON USING THIS PROGRAM TO SEE
PUT THE NUMBER III ONTO THE TOP OF THE PROGRAM STACK
GET THE FIRST ELEMENT OF THE PROGRAM STACK AND THE SECOND ELEMENT OF THE PROGRAM STACK AND IF THE SECOND ELEMENT OF THE PROGRAM STACK IS NOT ZERO JUMP TO THE INSTRUCTION THAT IS THE CURRENT INSTRUCTION NUMBER AND THE FIRST ELEMENT ADDED TOGETHER'S RESULT
PUT THE NUMBER NULLA ONTO THE TOP OF THE PROGRAM STACK
GET THE TOP ELEMENT OF THE STACK AND OUTPUT IT FOR THE CURRENT PERSON USING THIS PROGRAM TO SEE
Outputs I
for valid roman numerals in the range I-MMMCMXCIX
and NULLA
(0) or informs user input is not a valid roman numeral otherwise.
answered yesterday
Expired DataExpired Data
898216
898216
10
$begingroup$
I can't decide if this is the right tool for the job or not.
$endgroup$
– Vaelus
yesterday
4
$begingroup$
Is this the right tool for any job?
$endgroup$
– omzrs
yesterday
add a comment |
10
$begingroup$
I can't decide if this is the right tool for the job or not.
$endgroup$
– Vaelus
yesterday
4
$begingroup$
Is this the right tool for any job?
$endgroup$
– omzrs
yesterday
10
10
$begingroup$
I can't decide if this is the right tool for the job or not.
$endgroup$
– Vaelus
yesterday
$begingroup$
I can't decide if this is the right tool for the job or not.
$endgroup$
– Vaelus
yesterday
4
4
$begingroup$
Is this the right tool for any job?
$endgroup$
– omzrs
yesterday
$begingroup$
Is this the right tool for any job?
$endgroup$
– omzrs
yesterday
add a comment |
$begingroup$
C# (Visual C# Interactive Compiler), 79 109 bytes
This seems like a Regex challenge, I'm sure a shorter solution can be found...
s=>System.Text.RegularExpressions.Regex.IsMatch(s,"^M0,3(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)$")
Try it online!
$endgroup$
$begingroup$
Couldn't you shorten0,3
to,3
?
$endgroup$
– flawr
yesterday
$begingroup$
@flawr doesn't seem to capture anything then
$endgroup$
– Innat3
yesterday
1
$begingroup$
Ah sorry, only things like5,
work, but not,5
.
$endgroup$
– flawr
yesterday
2
$begingroup$
You can add it as compiler flag instead, so it's 72 bytes and the language should be changed to C# (Visual C# Interactive Compiler) with flag/u:System.Text.RegularExpressions.Regex
, like this answer :)
$endgroup$
– Kevin Cruijssen
yesterday
3
$begingroup$
Alternate regex:^M?M?M?(C[MD]|D?C?C?C?)(X[CL]|L?X?X?X?)(I[XV]|V?I?I?I?)$
. Same length, but looks weirder (which is the goal, right?)
$endgroup$
– Embodiment of Ignorance
yesterday
|
show 6 more comments
$begingroup$
C# (Visual C# Interactive Compiler), 79 109 bytes
This seems like a Regex challenge, I'm sure a shorter solution can be found...
s=>System.Text.RegularExpressions.Regex.IsMatch(s,"^M0,3(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)$")
Try it online!
$endgroup$
$begingroup$
Couldn't you shorten0,3
to,3
?
$endgroup$
– flawr
yesterday
$begingroup$
@flawr doesn't seem to capture anything then
$endgroup$
– Innat3
yesterday
1
$begingroup$
Ah sorry, only things like5,
work, but not,5
.
$endgroup$
– flawr
yesterday
2
$begingroup$
You can add it as compiler flag instead, so it's 72 bytes and the language should be changed to C# (Visual C# Interactive Compiler) with flag/u:System.Text.RegularExpressions.Regex
, like this answer :)
$endgroup$
– Kevin Cruijssen
yesterday
3
$begingroup$
Alternate regex:^M?M?M?(C[MD]|D?C?C?C?)(X[CL]|L?X?X?X?)(I[XV]|V?I?I?I?)$
. Same length, but looks weirder (which is the goal, right?)
$endgroup$
– Embodiment of Ignorance
yesterday
|
show 6 more comments
$begingroup$
C# (Visual C# Interactive Compiler), 79 109 bytes
This seems like a Regex challenge, I'm sure a shorter solution can be found...
s=>System.Text.RegularExpressions.Regex.IsMatch(s,"^M0,3(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)$")
Try it online!
$endgroup$
C# (Visual C# Interactive Compiler), 79 109 bytes
This seems like a Regex challenge, I'm sure a shorter solution can be found...
s=>System.Text.RegularExpressions.Regex.IsMatch(s,"^M0,3(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)$")
Try it online!
edited yesterday
answered yesterday
Innat3Innat3
2314
2314
$begingroup$
Couldn't you shorten0,3
to,3
?
$endgroup$
– flawr
yesterday
$begingroup$
@flawr doesn't seem to capture anything then
$endgroup$
– Innat3
yesterday
1
$begingroup$
Ah sorry, only things like5,
work, but not,5
.
$endgroup$
– flawr
yesterday
2
$begingroup$
You can add it as compiler flag instead, so it's 72 bytes and the language should be changed to C# (Visual C# Interactive Compiler) with flag/u:System.Text.RegularExpressions.Regex
, like this answer :)
$endgroup$
– Kevin Cruijssen
yesterday
3
$begingroup$
Alternate regex:^M?M?M?(C[MD]|D?C?C?C?)(X[CL]|L?X?X?X?)(I[XV]|V?I?I?I?)$
. Same length, but looks weirder (which is the goal, right?)
$endgroup$
– Embodiment of Ignorance
yesterday
|
show 6 more comments
$begingroup$
Couldn't you shorten0,3
to,3
?
$endgroup$
– flawr
yesterday
$begingroup$
@flawr doesn't seem to capture anything then
$endgroup$
– Innat3
yesterday
1
$begingroup$
Ah sorry, only things like5,
work, but not,5
.
$endgroup$
– flawr
yesterday
2
$begingroup$
You can add it as compiler flag instead, so it's 72 bytes and the language should be changed to C# (Visual C# Interactive Compiler) with flag/u:System.Text.RegularExpressions.Regex
, like this answer :)
$endgroup$
– Kevin Cruijssen
yesterday
3
$begingroup$
Alternate regex:^M?M?M?(C[MD]|D?C?C?C?)(X[CL]|L?X?X?X?)(I[XV]|V?I?I?I?)$
. Same length, but looks weirder (which is the goal, right?)
$endgroup$
– Embodiment of Ignorance
yesterday
$begingroup$
Couldn't you shorten
0,3
to ,3
?$endgroup$
– flawr
yesterday
$begingroup$
Couldn't you shorten
0,3
to ,3
?$endgroup$
– flawr
yesterday
$begingroup$
@flawr doesn't seem to capture anything then
$endgroup$
– Innat3
yesterday
$begingroup$
@flawr doesn't seem to capture anything then
$endgroup$
– Innat3
yesterday
1
1
$begingroup$
Ah sorry, only things like
5,
work, but not ,5
.$endgroup$
– flawr
yesterday
$begingroup$
Ah sorry, only things like
5,
work, but not ,5
.$endgroup$
– flawr
yesterday
2
2
$begingroup$
You can add it as compiler flag instead, so it's 72 bytes and the language should be changed to C# (Visual C# Interactive Compiler) with flag
/u:System.Text.RegularExpressions.Regex
, like this answer :)$endgroup$
– Kevin Cruijssen
yesterday
$begingroup$
You can add it as compiler flag instead, so it's 72 bytes and the language should be changed to C# (Visual C# Interactive Compiler) with flag
/u:System.Text.RegularExpressions.Regex
, like this answer :)$endgroup$
– Kevin Cruijssen
yesterday
3
3
$begingroup$
Alternate regex:
^M?M?M?(C[MD]|D?C?C?C?)(X[CL]|L?X?X?X?)(I[XV]|V?I?I?I?)$
. Same length, but looks weirder (which is the goal, right?)$endgroup$
– Embodiment of Ignorance
yesterday
$begingroup$
Alternate regex:
^M?M?M?(C[MD]|D?C?C?C?)(X[CL]|L?X?X?X?)(I[XV]|V?I?I?I?)$
. Same length, but looks weirder (which is the goal, right?)$endgroup$
– Embodiment of Ignorance
yesterday
|
show 6 more comments
$begingroup$
Java 8, 70 bytes
s->s.matches("M0,3(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)")
Port of @Innat3's C# answer, so make sure to upvote him!
Try it online.
Explanation:
s-> // Method with String parameter and boolean return-type
s.matches("...") // Check if the string matches the regex fully
// (which implicitly adds a leading "^" and trailing "$")
M0,3 // No, 1, 2, or 3 adjacent "M"
( | ) // Followed by either:
C[MD] // A "C" with an "M" or "D" after it
| // or:
D? // An optional "D"
C0,3 // Followed by no, 1, 2, or 3 adjacent "C"
( | ) // Followed by either:
X[CL] // An "X" with a "C" or "L" after it
| // or:
L? // An optional "L"
X0,3 // Followed by no, 1, 2, or 3 adjacent "X"
( | ) // Followed by either:
I[XV] // An "I" with an "X" or "V" after it
| // or:
V? // An optional "V"
I0,3 // Followed by no, 1, 2, or 3 adjacent "I"
$endgroup$
add a comment |
$begingroup$
Java 8, 70 bytes
s->s.matches("M0,3(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)")
Port of @Innat3's C# answer, so make sure to upvote him!
Try it online.
Explanation:
s-> // Method with String parameter and boolean return-type
s.matches("...") // Check if the string matches the regex fully
// (which implicitly adds a leading "^" and trailing "$")
M0,3 // No, 1, 2, or 3 adjacent "M"
( | ) // Followed by either:
C[MD] // A "C" with an "M" or "D" after it
| // or:
D? // An optional "D"
C0,3 // Followed by no, 1, 2, or 3 adjacent "C"
( | ) // Followed by either:
X[CL] // An "X" with a "C" or "L" after it
| // or:
L? // An optional "L"
X0,3 // Followed by no, 1, 2, or 3 adjacent "X"
( | ) // Followed by either:
I[XV] // An "I" with an "X" or "V" after it
| // or:
V? // An optional "V"
I0,3 // Followed by no, 1, 2, or 3 adjacent "I"
$endgroup$
add a comment |
$begingroup$
Java 8, 70 bytes
s->s.matches("M0,3(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)")
Port of @Innat3's C# answer, so make sure to upvote him!
Try it online.
Explanation:
s-> // Method with String parameter and boolean return-type
s.matches("...") // Check if the string matches the regex fully
// (which implicitly adds a leading "^" and trailing "$")
M0,3 // No, 1, 2, or 3 adjacent "M"
( | ) // Followed by either:
C[MD] // A "C" with an "M" or "D" after it
| // or:
D? // An optional "D"
C0,3 // Followed by no, 1, 2, or 3 adjacent "C"
( | ) // Followed by either:
X[CL] // An "X" with a "C" or "L" after it
| // or:
L? // An optional "L"
X0,3 // Followed by no, 1, 2, or 3 adjacent "X"
( | ) // Followed by either:
I[XV] // An "I" with an "X" or "V" after it
| // or:
V? // An optional "V"
I0,3 // Followed by no, 1, 2, or 3 adjacent "I"
$endgroup$
Java 8, 70 bytes
s->s.matches("M0,3(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)")
Port of @Innat3's C# answer, so make sure to upvote him!
Try it online.
Explanation:
s-> // Method with String parameter and boolean return-type
s.matches("...") // Check if the string matches the regex fully
// (which implicitly adds a leading "^" and trailing "$")
M0,3 // No, 1, 2, or 3 adjacent "M"
( | ) // Followed by either:
C[MD] // A "C" with an "M" or "D" after it
| // or:
D? // An optional "D"
C0,3 // Followed by no, 1, 2, or 3 adjacent "C"
( | ) // Followed by either:
X[CL] // An "X" with a "C" or "L" after it
| // or:
L? // An optional "L"
X0,3 // Followed by no, 1, 2, or 3 adjacent "X"
( | ) // Followed by either:
I[XV] // An "I" with an "X" or "V" after it
| // or:
V? // An optional "V"
I0,3 // Followed by no, 1, 2, or 3 adjacent "I"
answered yesterday
Kevin CruijssenKevin Cruijssen
42.7k571217
42.7k571217
add a comment |
add a comment |
$begingroup$
Wolfram Language (Mathematica), 35 bytes
Check[FromRomanNumeral@#<3999,1<0]&
Try it online!
5 bytes saved, thanks to @attinat
the limitation [1,3999]
unfortunateley costs 7 bytes...
here is the code for any roman number
Wolfram Language (Mathematica), 28 bytes
Check[FromRomanNumeral@#,F]&
Try it online!
the above code works for any number, not just [1,3999]
$endgroup$
2
$begingroup$
@ExpiredData "The input is a non-empty string that only comprises the charactersIVXLCDM
."
$endgroup$
– mathmandan
yesterday
$begingroup$
35 bytes.Boole
is also shorter (by one byte) than usingIf
in that way.
$endgroup$
– attinat
yesterday
add a comment |
$begingroup$
Wolfram Language (Mathematica), 35 bytes
Check[FromRomanNumeral@#<3999,1<0]&
Try it online!
5 bytes saved, thanks to @attinat
the limitation [1,3999]
unfortunateley costs 7 bytes...
here is the code for any roman number
Wolfram Language (Mathematica), 28 bytes
Check[FromRomanNumeral@#,F]&
Try it online!
the above code works for any number, not just [1,3999]
$endgroup$
2
$begingroup$
@ExpiredData "The input is a non-empty string that only comprises the charactersIVXLCDM
."
$endgroup$
– mathmandan
yesterday
$begingroup$
35 bytes.Boole
is also shorter (by one byte) than usingIf
in that way.
$endgroup$
– attinat
yesterday
add a comment |
$begingroup$
Wolfram Language (Mathematica), 35 bytes
Check[FromRomanNumeral@#<3999,1<0]&
Try it online!
5 bytes saved, thanks to @attinat
the limitation [1,3999]
unfortunateley costs 7 bytes...
here is the code for any roman number
Wolfram Language (Mathematica), 28 bytes
Check[FromRomanNumeral@#,F]&
Try it online!
the above code works for any number, not just [1,3999]
$endgroup$
Wolfram Language (Mathematica), 35 bytes
Check[FromRomanNumeral@#<3999,1<0]&
Try it online!
5 bytes saved, thanks to @attinat
the limitation [1,3999]
unfortunateley costs 7 bytes...
here is the code for any roman number
Wolfram Language (Mathematica), 28 bytes
Check[FromRomanNumeral@#,F]&
Try it online!
the above code works for any number, not just [1,3999]
edited 22 hours ago
answered yesterday
J42161217J42161217
14k21353
14k21353
2
$begingroup$
@ExpiredData "The input is a non-empty string that only comprises the charactersIVXLCDM
."
$endgroup$
– mathmandan
yesterday
$begingroup$
35 bytes.Boole
is also shorter (by one byte) than usingIf
in that way.
$endgroup$
– attinat
yesterday
add a comment |
2
$begingroup$
@ExpiredData "The input is a non-empty string that only comprises the charactersIVXLCDM
."
$endgroup$
– mathmandan
yesterday
$begingroup$
35 bytes.Boole
is also shorter (by one byte) than usingIf
in that way.
$endgroup$
– attinat
yesterday
2
2
$begingroup$
@ExpiredData "The input is a non-empty string that only comprises the characters
IVXLCDM
."$endgroup$
– mathmandan
yesterday
$begingroup$
@ExpiredData "The input is a non-empty string that only comprises the characters
IVXLCDM
."$endgroup$
– mathmandan
yesterday
$begingroup$
35 bytes.
Boole
is also shorter (by one byte) than using If
in that way.$endgroup$
– attinat
yesterday
$begingroup$
35 bytes.
Boole
is also shorter (by one byte) than using If
in that way.$endgroup$
– attinat
yesterday
add a comment |
$begingroup$
CP-1610 assembly (Intellivision), 52 ... 48 47 DECLEs1 = 59 bytes
Let's try this on a system that predates Perl by a good 7 years. :-)
Takes a pointer to a null-terminated string in R4. Sets the Zero flag if the input is a valid Roman numeral, or clears it otherwise.
ROMW 10 ; use 10-bit ROM width
ORG $4800 ; map this program at $4800
;; ------------------------------------------------------------- ;;
;; test code ;;
;; ------------------------------------------------------------- ;;
4800 EIS ; enable interrupts
4801 SDBD ; R5 = pointer into test case index
4802 MVII #ndx, R5
4805 MVII #$214, R3 ; R3 = backtab pointer
4807 MVII #11, R0 ; R0 = number of test cases
4809 loop SDBD ; R4 = pointer to next test case
480A MVI@ R5, R4
480B PSHR R0 ; save R0, R3, R5 onto the stack
480C PSHR R3
480D PSHR R5
480E CALL isRoman ; invoke our routine
4811 PULR R5 ; restore R5 and R3
4812 PULR R3
4813 MVII #$1A7, R0 ; use a white 'T' by default
4815 BEQ disp
4817 MVII #$137, R0 ; or a white 'F' is the Z flag was cleared
4819 disp MVO@ R0, R3 ; draw it
481A INCR R3 ; increment the backtab pointer
481B PULR R0 ; restore R0
481C DECR R0 ; and advance to the next test case, if any
481D BNEQ loop
481F DECR R7 ; loop forever
;; ------------------------------------------------------------- ;;
;; test cases ;;
;; ------------------------------------------------------------- ;;
4820 ndx BIDECLE test0, test1, test2, test3
4828 BIDECLE test4, test5, test6, test7, test8, test9, test10
; truthy
4836 test0 STRING "MCCXXXIV", 0
483F test1 STRING "CMLXXXVIII", 0
484A test2 STRING "DXIV", 0
484F test3 STRING "CI", 0
; falsy
4852 test4 STRING "MMIXVIII", 0
485B test5 STRING "IVX", 0
485F test6 STRING "IXV", 0
4863 test7 STRING "MMMM", 0
4868 test8 STRING "XXXVX", 0
486E test9 STRING "IVI", 0
4872 test10 STRING "VIV", 0
;; ------------------------------------------------------------- ;;
;; routine ;;
;; ------------------------------------------------------------- ;;
isRoman PROC
4876 PSHR R5 ; push the return address
4877 MOVR R7, R2 ; R2 = dummy 1st suffix
4878 MOVR R2, R5 ; R5 = pointer into table
4879 ADDI #@tbl-$+1,R5
487B @loop MVI@ R5, R1 ; R1 = main digit (M, C, X, I)
487C MVI@ R5, R3 ; R3 = prefix or 2nd suffix (-, D, L, V)
487D MVI@ R4, R0 ; R0 = next digit
487E CMPR R0, R3 ; if this is the prefix ...
487F BNEQ @main
4881 COMR R2 ; ... disable the suffixes
4882 COMR R3 ; by setting them to invalid values
4883 MVI@ R4, R0 ; and read R0 again
4884 @main CMPR R0, R1 ; if R0 is not equal to the main digit,
4885 BNEQ @back ; assume that this part is over
4887 MVI@ R4, R0 ; R0 = next digit
4888 CMPR R0, R1 ; if this is a 2nd occurrence
4889 BNEQ @suffix ; of the main digit ...
488B CMP@ R4, R1 ; ... it may be followed by a 3rd occurrence
488C BNEQ @back
488E MOVR R2, R0 ; if so, force the test below to succeed
488F @suffix CMPR R0, R2 ; otherwise, it may be either the 1st suffix
4890 BEQ @next
4892 CMPR R0, R3 ; or the 2nd suffix (these tests always fail
4893 BEQ @next ; if the suffixes were disabled above)
4895 @back DECR R4 ; the last digit either belongs to the next
; iteration or is invalid
4896 @next MOVR R1, R2 ; use the current main digit
; as the next 1st suffix
4897 SUBI #'I', R1 ; was it the last iteration? ...
4899 BNEQ @loop
489B CMP@ R4, R1 ; ... yes: make sure that we've also reached
; the end of the input
489C PULR R7 ; return
489D @tbl DECLE 'M', '-' ; table format: main digit, 2nd suffix
489F DECLE 'C', 'D'
48A1 DECLE 'X', 'L'
48A3 DECLE 'I', 'V'
ENDP
How?
The regular expression can be rewritten as 4 groups with the same structure, provided that #
is any invalid character that is guaranteed not be present in the input string.
+-------+---> main digit
| |
(M[##]|#?M0,3)(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)
|| |
|+--+-----> prefix or second suffix
|
+---------> first suffix
The first suffix of the group $N$ is the main digit of the group $N-1$. Therefore, we can store the patterns with the pair $(textmain_digit, textsecond_suffix)$ alone.
Our routine attempts to parse the input string character by character according to these patterns and eventually checks whether the end of the string is reached.
Output
screenshot of jzIntv
1. A CP-1610 opcode is encoded with a 10-bit value, known as a 'DECLE'. This routine is 47 DECLEs long, starting at $4876 and ending at $48A4 (included).
$endgroup$
$begingroup$
wouldn't this be one of the few places where fractional bytes are valid
$endgroup$
– ASCII-only
22 hours ago
$begingroup$
@ASCII-only I used to think so, but I don't know for sure. See the comments of this answer for some insight about this.
$endgroup$
– Arnauld
22 hours ago
$begingroup$
@ASCII-only Also, I've just found this post in meta that tends to confirm it's probably best to round to whole bytes.
$endgroup$
– Arnauld
21 hours ago
$begingroup$
ah, so it's only 10 bits when it's in RAM?
$endgroup$
– ASCII-only
21 hours ago
$begingroup$
The program is never stored in RAM, only in ROM. So it depends on the memory chips used in the cartridge. The CPU is designed to access either 10-bit or 16-bit ROM. The "ROMW 10" directive forces the compiler to generate code in 10-bit format.
$endgroup$
– Arnauld
21 hours ago
add a comment |
$begingroup$
CP-1610 assembly (Intellivision), 52 ... 48 47 DECLEs1 = 59 bytes
Let's try this on a system that predates Perl by a good 7 years. :-)
Takes a pointer to a null-terminated string in R4. Sets the Zero flag if the input is a valid Roman numeral, or clears it otherwise.
ROMW 10 ; use 10-bit ROM width
ORG $4800 ; map this program at $4800
;; ------------------------------------------------------------- ;;
;; test code ;;
;; ------------------------------------------------------------- ;;
4800 EIS ; enable interrupts
4801 SDBD ; R5 = pointer into test case index
4802 MVII #ndx, R5
4805 MVII #$214, R3 ; R3 = backtab pointer
4807 MVII #11, R0 ; R0 = number of test cases
4809 loop SDBD ; R4 = pointer to next test case
480A MVI@ R5, R4
480B PSHR R0 ; save R0, R3, R5 onto the stack
480C PSHR R3
480D PSHR R5
480E CALL isRoman ; invoke our routine
4811 PULR R5 ; restore R5 and R3
4812 PULR R3
4813 MVII #$1A7, R0 ; use a white 'T' by default
4815 BEQ disp
4817 MVII #$137, R0 ; or a white 'F' is the Z flag was cleared
4819 disp MVO@ R0, R3 ; draw it
481A INCR R3 ; increment the backtab pointer
481B PULR R0 ; restore R0
481C DECR R0 ; and advance to the next test case, if any
481D BNEQ loop
481F DECR R7 ; loop forever
;; ------------------------------------------------------------- ;;
;; test cases ;;
;; ------------------------------------------------------------- ;;
4820 ndx BIDECLE test0, test1, test2, test3
4828 BIDECLE test4, test5, test6, test7, test8, test9, test10
; truthy
4836 test0 STRING "MCCXXXIV", 0
483F test1 STRING "CMLXXXVIII", 0
484A test2 STRING "DXIV", 0
484F test3 STRING "CI", 0
; falsy
4852 test4 STRING "MMIXVIII", 0
485B test5 STRING "IVX", 0
485F test6 STRING "IXV", 0
4863 test7 STRING "MMMM", 0
4868 test8 STRING "XXXVX", 0
486E test9 STRING "IVI", 0
4872 test10 STRING "VIV", 0
;; ------------------------------------------------------------- ;;
;; routine ;;
;; ------------------------------------------------------------- ;;
isRoman PROC
4876 PSHR R5 ; push the return address
4877 MOVR R7, R2 ; R2 = dummy 1st suffix
4878 MOVR R2, R5 ; R5 = pointer into table
4879 ADDI #@tbl-$+1,R5
487B @loop MVI@ R5, R1 ; R1 = main digit (M, C, X, I)
487C MVI@ R5, R3 ; R3 = prefix or 2nd suffix (-, D, L, V)
487D MVI@ R4, R0 ; R0 = next digit
487E CMPR R0, R3 ; if this is the prefix ...
487F BNEQ @main
4881 COMR R2 ; ... disable the suffixes
4882 COMR R3 ; by setting them to invalid values
4883 MVI@ R4, R0 ; and read R0 again
4884 @main CMPR R0, R1 ; if R0 is not equal to the main digit,
4885 BNEQ @back ; assume that this part is over
4887 MVI@ R4, R0 ; R0 = next digit
4888 CMPR R0, R1 ; if this is a 2nd occurrence
4889 BNEQ @suffix ; of the main digit ...
488B CMP@ R4, R1 ; ... it may be followed by a 3rd occurrence
488C BNEQ @back
488E MOVR R2, R0 ; if so, force the test below to succeed
488F @suffix CMPR R0, R2 ; otherwise, it may be either the 1st suffix
4890 BEQ @next
4892 CMPR R0, R3 ; or the 2nd suffix (these tests always fail
4893 BEQ @next ; if the suffixes were disabled above)
4895 @back DECR R4 ; the last digit either belongs to the next
; iteration or is invalid
4896 @next MOVR R1, R2 ; use the current main digit
; as the next 1st suffix
4897 SUBI #'I', R1 ; was it the last iteration? ...
4899 BNEQ @loop
489B CMP@ R4, R1 ; ... yes: make sure that we've also reached
; the end of the input
489C PULR R7 ; return
489D @tbl DECLE 'M', '-' ; table format: main digit, 2nd suffix
489F DECLE 'C', 'D'
48A1 DECLE 'X', 'L'
48A3 DECLE 'I', 'V'
ENDP
How?
The regular expression can be rewritten as 4 groups with the same structure, provided that #
is any invalid character that is guaranteed not be present in the input string.
+-------+---> main digit
| |
(M[##]|#?M0,3)(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)
|| |
|+--+-----> prefix or second suffix
|
+---------> first suffix
The first suffix of the group $N$ is the main digit of the group $N-1$. Therefore, we can store the patterns with the pair $(textmain_digit, textsecond_suffix)$ alone.
Our routine attempts to parse the input string character by character according to these patterns and eventually checks whether the end of the string is reached.
Output
screenshot of jzIntv
1. A CP-1610 opcode is encoded with a 10-bit value, known as a 'DECLE'. This routine is 47 DECLEs long, starting at $4876 and ending at $48A4 (included).
$endgroup$
$begingroup$
wouldn't this be one of the few places where fractional bytes are valid
$endgroup$
– ASCII-only
22 hours ago
$begingroup$
@ASCII-only I used to think so, but I don't know for sure. See the comments of this answer for some insight about this.
$endgroup$
– Arnauld
22 hours ago
$begingroup$
@ASCII-only Also, I've just found this post in meta that tends to confirm it's probably best to round to whole bytes.
$endgroup$
– Arnauld
21 hours ago
$begingroup$
ah, so it's only 10 bits when it's in RAM?
$endgroup$
– ASCII-only
21 hours ago
$begingroup$
The program is never stored in RAM, only in ROM. So it depends on the memory chips used in the cartridge. The CPU is designed to access either 10-bit or 16-bit ROM. The "ROMW 10" directive forces the compiler to generate code in 10-bit format.
$endgroup$
– Arnauld
21 hours ago
add a comment |
$begingroup$
CP-1610 assembly (Intellivision), 52 ... 48 47 DECLEs1 = 59 bytes
Let's try this on a system that predates Perl by a good 7 years. :-)
Takes a pointer to a null-terminated string in R4. Sets the Zero flag if the input is a valid Roman numeral, or clears it otherwise.
ROMW 10 ; use 10-bit ROM width
ORG $4800 ; map this program at $4800
;; ------------------------------------------------------------- ;;
;; test code ;;
;; ------------------------------------------------------------- ;;
4800 EIS ; enable interrupts
4801 SDBD ; R5 = pointer into test case index
4802 MVII #ndx, R5
4805 MVII #$214, R3 ; R3 = backtab pointer
4807 MVII #11, R0 ; R0 = number of test cases
4809 loop SDBD ; R4 = pointer to next test case
480A MVI@ R5, R4
480B PSHR R0 ; save R0, R3, R5 onto the stack
480C PSHR R3
480D PSHR R5
480E CALL isRoman ; invoke our routine
4811 PULR R5 ; restore R5 and R3
4812 PULR R3
4813 MVII #$1A7, R0 ; use a white 'T' by default
4815 BEQ disp
4817 MVII #$137, R0 ; or a white 'F' is the Z flag was cleared
4819 disp MVO@ R0, R3 ; draw it
481A INCR R3 ; increment the backtab pointer
481B PULR R0 ; restore R0
481C DECR R0 ; and advance to the next test case, if any
481D BNEQ loop
481F DECR R7 ; loop forever
;; ------------------------------------------------------------- ;;
;; test cases ;;
;; ------------------------------------------------------------- ;;
4820 ndx BIDECLE test0, test1, test2, test3
4828 BIDECLE test4, test5, test6, test7, test8, test9, test10
; truthy
4836 test0 STRING "MCCXXXIV", 0
483F test1 STRING "CMLXXXVIII", 0
484A test2 STRING "DXIV", 0
484F test3 STRING "CI", 0
; falsy
4852 test4 STRING "MMIXVIII", 0
485B test5 STRING "IVX", 0
485F test6 STRING "IXV", 0
4863 test7 STRING "MMMM", 0
4868 test8 STRING "XXXVX", 0
486E test9 STRING "IVI", 0
4872 test10 STRING "VIV", 0
;; ------------------------------------------------------------- ;;
;; routine ;;
;; ------------------------------------------------------------- ;;
isRoman PROC
4876 PSHR R5 ; push the return address
4877 MOVR R7, R2 ; R2 = dummy 1st suffix
4878 MOVR R2, R5 ; R5 = pointer into table
4879 ADDI #@tbl-$+1,R5
487B @loop MVI@ R5, R1 ; R1 = main digit (M, C, X, I)
487C MVI@ R5, R3 ; R3 = prefix or 2nd suffix (-, D, L, V)
487D MVI@ R4, R0 ; R0 = next digit
487E CMPR R0, R3 ; if this is the prefix ...
487F BNEQ @main
4881 COMR R2 ; ... disable the suffixes
4882 COMR R3 ; by setting them to invalid values
4883 MVI@ R4, R0 ; and read R0 again
4884 @main CMPR R0, R1 ; if R0 is not equal to the main digit,
4885 BNEQ @back ; assume that this part is over
4887 MVI@ R4, R0 ; R0 = next digit
4888 CMPR R0, R1 ; if this is a 2nd occurrence
4889 BNEQ @suffix ; of the main digit ...
488B CMP@ R4, R1 ; ... it may be followed by a 3rd occurrence
488C BNEQ @back
488E MOVR R2, R0 ; if so, force the test below to succeed
488F @suffix CMPR R0, R2 ; otherwise, it may be either the 1st suffix
4890 BEQ @next
4892 CMPR R0, R3 ; or the 2nd suffix (these tests always fail
4893 BEQ @next ; if the suffixes were disabled above)
4895 @back DECR R4 ; the last digit either belongs to the next
; iteration or is invalid
4896 @next MOVR R1, R2 ; use the current main digit
; as the next 1st suffix
4897 SUBI #'I', R1 ; was it the last iteration? ...
4899 BNEQ @loop
489B CMP@ R4, R1 ; ... yes: make sure that we've also reached
; the end of the input
489C PULR R7 ; return
489D @tbl DECLE 'M', '-' ; table format: main digit, 2nd suffix
489F DECLE 'C', 'D'
48A1 DECLE 'X', 'L'
48A3 DECLE 'I', 'V'
ENDP
How?
The regular expression can be rewritten as 4 groups with the same structure, provided that #
is any invalid character that is guaranteed not be present in the input string.
+-------+---> main digit
| |
(M[##]|#?M0,3)(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)
|| |
|+--+-----> prefix or second suffix
|
+---------> first suffix
The first suffix of the group $N$ is the main digit of the group $N-1$. Therefore, we can store the patterns with the pair $(textmain_digit, textsecond_suffix)$ alone.
Our routine attempts to parse the input string character by character according to these patterns and eventually checks whether the end of the string is reached.
Output
screenshot of jzIntv
1. A CP-1610 opcode is encoded with a 10-bit value, known as a 'DECLE'. This routine is 47 DECLEs long, starting at $4876 and ending at $48A4 (included).
$endgroup$
CP-1610 assembly (Intellivision), 52 ... 48 47 DECLEs1 = 59 bytes
Let's try this on a system that predates Perl by a good 7 years. :-)
Takes a pointer to a null-terminated string in R4. Sets the Zero flag if the input is a valid Roman numeral, or clears it otherwise.
ROMW 10 ; use 10-bit ROM width
ORG $4800 ; map this program at $4800
;; ------------------------------------------------------------- ;;
;; test code ;;
;; ------------------------------------------------------------- ;;
4800 EIS ; enable interrupts
4801 SDBD ; R5 = pointer into test case index
4802 MVII #ndx, R5
4805 MVII #$214, R3 ; R3 = backtab pointer
4807 MVII #11, R0 ; R0 = number of test cases
4809 loop SDBD ; R4 = pointer to next test case
480A MVI@ R5, R4
480B PSHR R0 ; save R0, R3, R5 onto the stack
480C PSHR R3
480D PSHR R5
480E CALL isRoman ; invoke our routine
4811 PULR R5 ; restore R5 and R3
4812 PULR R3
4813 MVII #$1A7, R0 ; use a white 'T' by default
4815 BEQ disp
4817 MVII #$137, R0 ; or a white 'F' is the Z flag was cleared
4819 disp MVO@ R0, R3 ; draw it
481A INCR R3 ; increment the backtab pointer
481B PULR R0 ; restore R0
481C DECR R0 ; and advance to the next test case, if any
481D BNEQ loop
481F DECR R7 ; loop forever
;; ------------------------------------------------------------- ;;
;; test cases ;;
;; ------------------------------------------------------------- ;;
4820 ndx BIDECLE test0, test1, test2, test3
4828 BIDECLE test4, test5, test6, test7, test8, test9, test10
; truthy
4836 test0 STRING "MCCXXXIV", 0
483F test1 STRING "CMLXXXVIII", 0
484A test2 STRING "DXIV", 0
484F test3 STRING "CI", 0
; falsy
4852 test4 STRING "MMIXVIII", 0
485B test5 STRING "IVX", 0
485F test6 STRING "IXV", 0
4863 test7 STRING "MMMM", 0
4868 test8 STRING "XXXVX", 0
486E test9 STRING "IVI", 0
4872 test10 STRING "VIV", 0
;; ------------------------------------------------------------- ;;
;; routine ;;
;; ------------------------------------------------------------- ;;
isRoman PROC
4876 PSHR R5 ; push the return address
4877 MOVR R7, R2 ; R2 = dummy 1st suffix
4878 MOVR R2, R5 ; R5 = pointer into table
4879 ADDI #@tbl-$+1,R5
487B @loop MVI@ R5, R1 ; R1 = main digit (M, C, X, I)
487C MVI@ R5, R3 ; R3 = prefix or 2nd suffix (-, D, L, V)
487D MVI@ R4, R0 ; R0 = next digit
487E CMPR R0, R3 ; if this is the prefix ...
487F BNEQ @main
4881 COMR R2 ; ... disable the suffixes
4882 COMR R3 ; by setting them to invalid values
4883 MVI@ R4, R0 ; and read R0 again
4884 @main CMPR R0, R1 ; if R0 is not equal to the main digit,
4885 BNEQ @back ; assume that this part is over
4887 MVI@ R4, R0 ; R0 = next digit
4888 CMPR R0, R1 ; if this is a 2nd occurrence
4889 BNEQ @suffix ; of the main digit ...
488B CMP@ R4, R1 ; ... it may be followed by a 3rd occurrence
488C BNEQ @back
488E MOVR R2, R0 ; if so, force the test below to succeed
488F @suffix CMPR R0, R2 ; otherwise, it may be either the 1st suffix
4890 BEQ @next
4892 CMPR R0, R3 ; or the 2nd suffix (these tests always fail
4893 BEQ @next ; if the suffixes were disabled above)
4895 @back DECR R4 ; the last digit either belongs to the next
; iteration or is invalid
4896 @next MOVR R1, R2 ; use the current main digit
; as the next 1st suffix
4897 SUBI #'I', R1 ; was it the last iteration? ...
4899 BNEQ @loop
489B CMP@ R4, R1 ; ... yes: make sure that we've also reached
; the end of the input
489C PULR R7 ; return
489D @tbl DECLE 'M', '-' ; table format: main digit, 2nd suffix
489F DECLE 'C', 'D'
48A1 DECLE 'X', 'L'
48A3 DECLE 'I', 'V'
ENDP
How?
The regular expression can be rewritten as 4 groups with the same structure, provided that #
is any invalid character that is guaranteed not be present in the input string.
+-------+---> main digit
| |
(M[##]|#?M0,3)(C[MD]|D?C0,3)(X[CL]|L?X0,3)(I[XV]|V?I0,3)
|| |
|+--+-----> prefix or second suffix
|
+---------> first suffix
The first suffix of the group $N$ is the main digit of the group $N-1$. Therefore, we can store the patterns with the pair $(textmain_digit, textsecond_suffix)$ alone.
Our routine attempts to parse the input string character by character according to these patterns and eventually checks whether the end of the string is reached.
Output
screenshot of jzIntv
1. A CP-1610 opcode is encoded with a 10-bit value, known as a 'DECLE'. This routine is 47 DECLEs long, starting at $4876 and ending at $48A4 (included).
edited 18 hours ago
answered yesterday
ArnauldArnauld
80.9k797334
80.9k797334
$begingroup$
wouldn't this be one of the few places where fractional bytes are valid
$endgroup$
– ASCII-only
22 hours ago
$begingroup$
@ASCII-only I used to think so, but I don't know for sure. See the comments of this answer for some insight about this.
$endgroup$
– Arnauld
22 hours ago
$begingroup$
@ASCII-only Also, I've just found this post in meta that tends to confirm it's probably best to round to whole bytes.
$endgroup$
– Arnauld
21 hours ago
$begingroup$
ah, so it's only 10 bits when it's in RAM?
$endgroup$
– ASCII-only
21 hours ago
$begingroup$
The program is never stored in RAM, only in ROM. So it depends on the memory chips used in the cartridge. The CPU is designed to access either 10-bit or 16-bit ROM. The "ROMW 10" directive forces the compiler to generate code in 10-bit format.
$endgroup$
– Arnauld
21 hours ago
add a comment |
$begingroup$
wouldn't this be one of the few places where fractional bytes are valid
$endgroup$
– ASCII-only
22 hours ago
$begingroup$
@ASCII-only I used to think so, but I don't know for sure. See the comments of this answer for some insight about this.
$endgroup$
– Arnauld
22 hours ago
$begingroup$
@ASCII-only Also, I've just found this post in meta that tends to confirm it's probably best to round to whole bytes.
$endgroup$
– Arnauld
21 hours ago
$begingroup$
ah, so it's only 10 bits when it's in RAM?
$endgroup$
– ASCII-only
21 hours ago
$begingroup$
The program is never stored in RAM, only in ROM. So it depends on the memory chips used in the cartridge. The CPU is designed to access either 10-bit or 16-bit ROM. The "ROMW 10" directive forces the compiler to generate code in 10-bit format.
$endgroup$
– Arnauld
21 hours ago
$begingroup$
wouldn't this be one of the few places where fractional bytes are valid
$endgroup$
– ASCII-only
22 hours ago
$begingroup$
wouldn't this be one of the few places where fractional bytes are valid
$endgroup$
– ASCII-only
22 hours ago
$begingroup$
@ASCII-only I used to think so, but I don't know for sure. See the comments of this answer for some insight about this.
$endgroup$
– Arnauld
22 hours ago
$begingroup$
@ASCII-only I used to think so, but I don't know for sure. See the comments of this answer for some insight about this.
$endgroup$
– Arnauld
22 hours ago
$begingroup$
@ASCII-only Also, I've just found this post in meta that tends to confirm it's probably best to round to whole bytes.
$endgroup$
– Arnauld
21 hours ago
$begingroup$
@ASCII-only Also, I've just found this post in meta that tends to confirm it's probably best to round to whole bytes.
$endgroup$
– Arnauld
21 hours ago
$begingroup$
ah, so it's only 10 bits when it's in RAM?
$endgroup$
– ASCII-only
21 hours ago
$begingroup$
ah, so it's only 10 bits when it's in RAM?
$endgroup$
– ASCII-only
21 hours ago
$begingroup$
The program is never stored in RAM, only in ROM. So it depends on the memory chips used in the cartridge. The CPU is designed to access either 10-bit or 16-bit ROM. The "ROMW 10" directive forces the compiler to generate code in 10-bit format.
$endgroup$
– Arnauld
21 hours ago
$begingroup$
The program is never stored in RAM, only in ROM. So it depends on the memory chips used in the cartridge. The CPU is designed to access either 10-bit or 16-bit ROM. The "ROMW 10" directive forces the compiler to generate code in 10-bit format.
$endgroup$
– Arnauld
21 hours ago
add a comment |
$begingroup$
R, 74 71 56 bytes
Thanks to @RobinRyder, @Giuseppe, & @MickyT for their suggestions how to use grep effectively with R's built in as.roman
.
sub("^M(.+)","\1",scan(,""))%in%paste(as.roman(1:2999))
Try it online!
$endgroup$
$begingroup$
as.roman
won't work anyway, since it only works up to3899
for some reason.
$endgroup$
– Giuseppe
yesterday
$begingroup$
I really should read the documentation better, Probably because 4000 doesn't have a definite representation in Roman, so how'd one do 3900. This is similar to 390 and now I just found an issue with my grep where I'd have to anchor the pattern.
$endgroup$
– CT Hall
yesterday
$begingroup$
@Giuseppe, addressed, using the same regex as the other answers.
$endgroup$
– CT Hall
yesterday
$begingroup$
I wonder if there's a way to use.romans
here...probably not.
$endgroup$
– Giuseppe
yesterday
2
$begingroup$
66 bytes usingas.roman
: first strip the initialM
if there is one, then check whether the result is inas.roman(1:2999)
. This requires special handling of the case where the input isM
.
$endgroup$
– Robin Ryder
yesterday
|
show 10 more comments
$begingroup$
R, 74 71 56 bytes
Thanks to @RobinRyder, @Giuseppe, & @MickyT for their suggestions how to use grep effectively with R's built in as.roman
.
sub("^M(.+)","\1",scan(,""))%in%paste(as.roman(1:2999))
Try it online!
$endgroup$
$begingroup$
as.roman
won't work anyway, since it only works up to3899
for some reason.
$endgroup$
– Giuseppe
yesterday
$begingroup$
I really should read the documentation better, Probably because 4000 doesn't have a definite representation in Roman, so how'd one do 3900. This is similar to 390 and now I just found an issue with my grep where I'd have to anchor the pattern.
$endgroup$
– CT Hall
yesterday
$begingroup$
@Giuseppe, addressed, using the same regex as the other answers.
$endgroup$
– CT Hall
yesterday
$begingroup$
I wonder if there's a way to use.romans
here...probably not.
$endgroup$
– Giuseppe
yesterday
2
$begingroup$
66 bytes usingas.roman
: first strip the initialM
if there is one, then check whether the result is inas.roman(1:2999)
. This requires special handling of the case where the input isM
.
$endgroup$
– Robin Ryder
yesterday
|
show 10 more comments
$begingroup$
R, 74 71 56 bytes
Thanks to @RobinRyder, @Giuseppe, & @MickyT for their suggestions how to use grep effectively with R's built in as.roman
.
sub("^M(.+)","\1",scan(,""))%in%paste(as.roman(1:2999))
Try it online!
$endgroup$
R, 74 71 56 bytes
Thanks to @RobinRyder, @Giuseppe, & @MickyT for their suggestions how to use grep effectively with R's built in as.roman
.
sub("^M(.+)","\1",scan(,""))%in%paste(as.roman(1:2999))
Try it online!
edited yesterday
answered yesterday
CT HallCT Hall
51110
51110
$begingroup$
as.roman
won't work anyway, since it only works up to3899
for some reason.
$endgroup$
– Giuseppe
yesterday
$begingroup$
I really should read the documentation better, Probably because 4000 doesn't have a definite representation in Roman, so how'd one do 3900. This is similar to 390 and now I just found an issue with my grep where I'd have to anchor the pattern.
$endgroup$
– CT Hall
yesterday
$begingroup$
@Giuseppe, addressed, using the same regex as the other answers.
$endgroup$
– CT Hall
yesterday
$begingroup$
I wonder if there's a way to use.romans
here...probably not.
$endgroup$
– Giuseppe
yesterday
2
$begingroup$
66 bytes usingas.roman
: first strip the initialM
if there is one, then check whether the result is inas.roman(1:2999)
. This requires special handling of the case where the input isM
.
$endgroup$
– Robin Ryder
yesterday
|
show 10 more comments
$begingroup$
as.roman
won't work anyway, since it only works up to3899
for some reason.
$endgroup$
– Giuseppe
yesterday
$begingroup$
I really should read the documentation better, Probably because 4000 doesn't have a definite representation in Roman, so how'd one do 3900. This is similar to 390 and now I just found an issue with my grep where I'd have to anchor the pattern.
$endgroup$
– CT Hall
yesterday
$begingroup$
@Giuseppe, addressed, using the same regex as the other answers.
$endgroup$
– CT Hall
yesterday
$begingroup$
I wonder if there's a way to use.romans
here...probably not.
$endgroup$
– Giuseppe
yesterday
2
$begingroup$
66 bytes usingas.roman
: first strip the initialM
if there is one, then check whether the result is inas.roman(1:2999)
. This requires special handling of the case where the input isM
.
$endgroup$
– Robin Ryder
yesterday
$begingroup$
as.roman
won't work anyway, since it only works up to 3899
for some reason.$endgroup$
– Giuseppe
yesterday
$begingroup$
as.roman
won't work anyway, since it only works up to 3899
for some reason.$endgroup$
– Giuseppe
yesterday
$begingroup$
I really should read the documentation better, Probably because 4000 doesn't have a definite representation in Roman, so how'd one do 3900. This is similar to 390 and now I just found an issue with my grep where I'd have to anchor the pattern.
$endgroup$
– CT Hall
yesterday
$begingroup$
I really should read the documentation better, Probably because 4000 doesn't have a definite representation in Roman, so how'd one do 3900. This is similar to 390 and now I just found an issue with my grep where I'd have to anchor the pattern.
$endgroup$
– CT Hall
yesterday
$begingroup$
@Giuseppe, addressed, using the same regex as the other answers.
$endgroup$
– CT Hall
yesterday
$begingroup$
@Giuseppe, addressed, using the same regex as the other answers.
$endgroup$
– CT Hall
yesterday
$begingroup$
I wonder if there's a way to use
.romans
here...probably not.$endgroup$
– Giuseppe
yesterday
$begingroup$
I wonder if there's a way to use
.romans
here...probably not.$endgroup$
– Giuseppe
yesterday
2
2
$begingroup$
66 bytes using
as.roman
: first strip the initial M
if there is one, then check whether the result is in as.roman(1:2999)
. This requires special handling of the case where the input is M
.$endgroup$
– Robin Ryder
yesterday
$begingroup$
66 bytes using
as.roman
: first strip the initial M
if there is one, then check whether the result is in as.roman(1:2999)
. This requires special handling of the case where the input is M
.$endgroup$
– Robin Ryder
yesterday
|
show 10 more comments
$begingroup$
Wolfram Language (Mathematica), 32 bytes
RomanNumeral@Range@3999~Count~#&
Try it online!
$endgroup$
add a comment |
$begingroup$
Wolfram Language (Mathematica), 32 bytes
RomanNumeral@Range@3999~Count~#&
Try it online!
$endgroup$
add a comment |
$begingroup$
Wolfram Language (Mathematica), 32 bytes
RomanNumeral@Range@3999~Count~#&
Try it online!
$endgroup$
Wolfram Language (Mathematica), 32 bytes
RomanNumeral@Range@3999~Count~#&
Try it online!
answered yesterday
Expired DataExpired Data
898216
898216
add a comment |
add a comment |
$begingroup$
Jelly, 48 47 46 bytes
-1 thanks to Nick Kennedy
5Żo7;“ÆæC‘b3ð“IVXLCDM”ị@3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ
A monadic Link accepting a non-empty list of characters consisting only of IVXLCDM
which yields either 1
(when it's a valid Roman numeral between $1$ and $3999$) or 0
(if not).
Try it online! Or see the test-suite.
How?
Needs updating...
7R;“¿ç‘ḃ2ŒQ€6¦ị - Link 1, acceptable "digits": list of characters e.g. "IVX"
7R - range of seven [1,2,3,4,5,6,7]
“¿ç‘ - list of code-page indices [11,23]
; - concatenate [1,2,3,4,5,6,7,11,23]
ḃ2 - to bijective base two [[1],[2],[1,1],[1,2],[2,1],[2,2],[1,1,1],[2,1,1],[2,1,1,1]]
¦ - sparse application...
6 - ...to indices: six
ŒQ€ - ...do: for €ach: distinct sieve ...,[1,0],...
ị - index into input ["I","V","II", "IV", "VI", "IX", "III", "VII", "VIII" ]
“IVXLCDM”Ç3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ - Main Link: list of characters
“IVXLCDM” - list of characters
3Ƥ - for infixes of length three: ("IVX","VXL","XLC","LCD","CDM")
Ç - call the last Link (1) as a monad
m2 - modulo two slice (results for "IVX", "XLC", and "CDM" only)
¤ - nilad followed by link(s) as a nilad:
”M - character 'M'
Ɱ3 - map across [1,2,3] with:
ẋ - repeat -> ["M", "MM", "MMM"]
ṭ - tack
Ż€ - prepend a zero to each
Ṛ - reverse
- -- now we have the table:
- 0 M MM MMM
- 0 C D CC CD DC CM CCC DCC DCCC
- 0 X L XX XL LX XC XXX LXX LXXX
- 0 I V II IV VI IX III VII VIII
Œp - Cartesian product -> [[0,0,0,0],[0,0,0,"I"],...,["M","CM",0,"IV"],...]
F€ - flatten €ach -> [[0,0,0,0],[0,0,0,'I'],...,['M','C','M',0,'I','V'],...]
ḟ€0 - filter out the zeros from €ach -> ["","I",...,"MCMIV",...]
ċ - count occurrences of the input
$endgroup$
$begingroup$
There seems to be a redundant space on the first line. Another byte. Another byte can be saved by using a simpler first line. Try it online!
$endgroup$
– Nick Kennedy
23 hours ago
$begingroup$
Thanks, I've saved one more from it.
$endgroup$
– Jonathan Allan
21 hours ago
add a comment |
$begingroup$
Jelly, 48 47 46 bytes
-1 thanks to Nick Kennedy
5Żo7;“ÆæC‘b3ð“IVXLCDM”ị@3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ
A monadic Link accepting a non-empty list of characters consisting only of IVXLCDM
which yields either 1
(when it's a valid Roman numeral between $1$ and $3999$) or 0
(if not).
Try it online! Or see the test-suite.
How?
Needs updating...
7R;“¿ç‘ḃ2ŒQ€6¦ị - Link 1, acceptable "digits": list of characters e.g. "IVX"
7R - range of seven [1,2,3,4,5,6,7]
“¿ç‘ - list of code-page indices [11,23]
; - concatenate [1,2,3,4,5,6,7,11,23]
ḃ2 - to bijective base two [[1],[2],[1,1],[1,2],[2,1],[2,2],[1,1,1],[2,1,1],[2,1,1,1]]
¦ - sparse application...
6 - ...to indices: six
ŒQ€ - ...do: for €ach: distinct sieve ...,[1,0],...
ị - index into input ["I","V","II", "IV", "VI", "IX", "III", "VII", "VIII" ]
“IVXLCDM”Ç3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ - Main Link: list of characters
“IVXLCDM” - list of characters
3Ƥ - for infixes of length three: ("IVX","VXL","XLC","LCD","CDM")
Ç - call the last Link (1) as a monad
m2 - modulo two slice (results for "IVX", "XLC", and "CDM" only)
¤ - nilad followed by link(s) as a nilad:
”M - character 'M'
Ɱ3 - map across [1,2,3] with:
ẋ - repeat -> ["M", "MM", "MMM"]
ṭ - tack
Ż€ - prepend a zero to each
Ṛ - reverse
- -- now we have the table:
- 0 M MM MMM
- 0 C D CC CD DC CM CCC DCC DCCC
- 0 X L XX XL LX XC XXX LXX LXXX
- 0 I V II IV VI IX III VII VIII
Œp - Cartesian product -> [[0,0,0,0],[0,0,0,"I"],...,["M","CM",0,"IV"],...]
F€ - flatten €ach -> [[0,0,0,0],[0,0,0,'I'],...,['M','C','M',0,'I','V'],...]
ḟ€0 - filter out the zeros from €ach -> ["","I",...,"MCMIV",...]
ċ - count occurrences of the input
$endgroup$
$begingroup$
There seems to be a redundant space on the first line. Another byte. Another byte can be saved by using a simpler first line. Try it online!
$endgroup$
– Nick Kennedy
23 hours ago
$begingroup$
Thanks, I've saved one more from it.
$endgroup$
– Jonathan Allan
21 hours ago
add a comment |
$begingroup$
Jelly, 48 47 46 bytes
-1 thanks to Nick Kennedy
5Żo7;“ÆæC‘b3ð“IVXLCDM”ị@3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ
A monadic Link accepting a non-empty list of characters consisting only of IVXLCDM
which yields either 1
(when it's a valid Roman numeral between $1$ and $3999$) or 0
(if not).
Try it online! Or see the test-suite.
How?
Needs updating...
7R;“¿ç‘ḃ2ŒQ€6¦ị - Link 1, acceptable "digits": list of characters e.g. "IVX"
7R - range of seven [1,2,3,4,5,6,7]
“¿ç‘ - list of code-page indices [11,23]
; - concatenate [1,2,3,4,5,6,7,11,23]
ḃ2 - to bijective base two [[1],[2],[1,1],[1,2],[2,1],[2,2],[1,1,1],[2,1,1],[2,1,1,1]]
¦ - sparse application...
6 - ...to indices: six
ŒQ€ - ...do: for €ach: distinct sieve ...,[1,0],...
ị - index into input ["I","V","II", "IV", "VI", "IX", "III", "VII", "VIII" ]
“IVXLCDM”Ç3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ - Main Link: list of characters
“IVXLCDM” - list of characters
3Ƥ - for infixes of length three: ("IVX","VXL","XLC","LCD","CDM")
Ç - call the last Link (1) as a monad
m2 - modulo two slice (results for "IVX", "XLC", and "CDM" only)
¤ - nilad followed by link(s) as a nilad:
”M - character 'M'
Ɱ3 - map across [1,2,3] with:
ẋ - repeat -> ["M", "MM", "MMM"]
ṭ - tack
Ż€ - prepend a zero to each
Ṛ - reverse
- -- now we have the table:
- 0 M MM MMM
- 0 C D CC CD DC CM CCC DCC DCCC
- 0 X L XX XL LX XC XXX LXX LXXX
- 0 I V II IV VI IX III VII VIII
Œp - Cartesian product -> [[0,0,0,0],[0,0,0,"I"],...,["M","CM",0,"IV"],...]
F€ - flatten €ach -> [[0,0,0,0],[0,0,0,'I'],...,['M','C','M',0,'I','V'],...]
ḟ€0 - filter out the zeros from €ach -> ["","I",...,"MCMIV",...]
ċ - count occurrences of the input
$endgroup$
Jelly, 48 47 46 bytes
-1 thanks to Nick Kennedy
5Żo7;“ÆæC‘b3ð“IVXLCDM”ị@3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ
A monadic Link accepting a non-empty list of characters consisting only of IVXLCDM
which yields either 1
(when it's a valid Roman numeral between $1$ and $3999$) or 0
(if not).
Try it online! Or see the test-suite.
How?
Needs updating...
7R;“¿ç‘ḃ2ŒQ€6¦ị - Link 1, acceptable "digits": list of characters e.g. "IVX"
7R - range of seven [1,2,3,4,5,6,7]
“¿ç‘ - list of code-page indices [11,23]
; - concatenate [1,2,3,4,5,6,7,11,23]
ḃ2 - to bijective base two [[1],[2],[1,1],[1,2],[2,1],[2,2],[1,1,1],[2,1,1],[2,1,1,1]]
¦ - sparse application...
6 - ...to indices: six
ŒQ€ - ...do: for €ach: distinct sieve ...,[1,0],...
ị - index into input ["I","V","II", "IV", "VI", "IX", "III", "VII", "VIII" ]
“IVXLCDM”Ç3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ - Main Link: list of characters
“IVXLCDM” - list of characters
3Ƥ - for infixes of length three: ("IVX","VXL","XLC","LCD","CDM")
Ç - call the last Link (1) as a monad
m2 - modulo two slice (results for "IVX", "XLC", and "CDM" only)
¤ - nilad followed by link(s) as a nilad:
”M - character 'M'
Ɱ3 - map across [1,2,3] with:
ẋ - repeat -> ["M", "MM", "MMM"]
ṭ - tack
Ż€ - prepend a zero to each
Ṛ - reverse
- -- now we have the table:
- 0 M MM MMM
- 0 C D CC CD DC CM CCC DCC DCCC
- 0 X L XX XL LX XC XXX LXX LXXX
- 0 I V II IV VI IX III VII VIII
Œp - Cartesian product -> [[0,0,0,0],[0,0,0,"I"],...,["M","CM",0,"IV"],...]
F€ - flatten €ach -> [[0,0,0,0],[0,0,0,'I'],...,['M','C','M',0,'I','V'],...]
ḟ€0 - filter out the zeros from €ach -> ["","I",...,"MCMIV",...]
ċ - count occurrences of the input
edited 22 hours ago
answered yesterday
Jonathan AllanJonathan Allan
54.2k537174
54.2k537174
$begingroup$
There seems to be a redundant space on the first line. Another byte. Another byte can be saved by using a simpler first line. Try it online!
$endgroup$
– Nick Kennedy
23 hours ago
$begingroup$
Thanks, I've saved one more from it.
$endgroup$
– Jonathan Allan
21 hours ago
add a comment |
$begingroup$
There seems to be a redundant space on the first line. Another byte. Another byte can be saved by using a simpler first line. Try it online!
$endgroup$
– Nick Kennedy
23 hours ago
$begingroup$
Thanks, I've saved one more from it.
$endgroup$
– Jonathan Allan
21 hours ago
$begingroup$
There seems to be a redundant space on the first line. Another byte. Another byte can be saved by using a simpler first line. Try it online!
$endgroup$
– Nick Kennedy
23 hours ago
$begingroup$
There seems to be a redundant space on the first line. Another byte. Another byte can be saved by using a simpler first line. Try it online!
$endgroup$
– Nick Kennedy
23 hours ago
$begingroup$
Thanks, I've saved one more from it.
$endgroup$
– Jonathan Allan
21 hours ago
$begingroup$
Thanks, I've saved one more from it.
$endgroup$
– Jonathan Allan
21 hours ago
add a comment |
$begingroup$
Perl 5 (-p
), 57 bytes
$_=/^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$/&!/(.)13/
TIO
- uses almost the same regular expression except
0,3
quantifier was changed by*
&!/(.)13/
to ensure the same character can't occur 4 times in a row.- can't be golfed with
-/(.)13/
because would give-1
forIIIIVI
for example
$endgroup$
add a comment |
$begingroup$
Perl 5 (-p
), 57 bytes
$_=/^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$/&!/(.)13/
TIO
- uses almost the same regular expression except
0,3
quantifier was changed by*
&!/(.)13/
to ensure the same character can't occur 4 times in a row.- can't be golfed with
-/(.)13/
because would give-1
forIIIIVI
for example
$endgroup$
add a comment |
$begingroup$
Perl 5 (-p
), 57 bytes
$_=/^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$/&!/(.)13/
TIO
- uses almost the same regular expression except
0,3
quantifier was changed by*
&!/(.)13/
to ensure the same character can't occur 4 times in a row.- can't be golfed with
-/(.)13/
because would give-1
forIIIIVI
for example
$endgroup$
Perl 5 (-p
), 57 bytes
$_=/^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$/&!/(.)13/
TIO
- uses almost the same regular expression except
0,3
quantifier was changed by*
&!/(.)13/
to ensure the same character can't occur 4 times in a row.- can't be golfed with
-/(.)13/
because would give-1
forIIIIVI
for example
edited yesterday
answered yesterday
Nahuel FouilleulNahuel Fouilleul
3,035211
3,035211
add a comment |
add a comment |
$begingroup$
Python 2, 81 bytes
import re
re.compile('M,3(D?C,3|C[DM])(L?X,3|X[LC])(V?I,3|I[VX])$').match
Try it online!
Let's look at the last part of the regex, which matching the Roman numerals up to 9 (including the empty string)
V?I,3|I[VX]
This has two alternatives separated by |
:
V?I,3
: An optionalV
followed by up to 3I
's. This matches the empty stringI
,II
,III
,V
,VI
,VII
,VIII
.I[VX]
: AnI
followed by aV
orX
. This matchesIV
andIX
.
The same things with X,L,C
matching the tens, with C,D,M
matches the hundreds, and finally ^M,3
allows up to 3 M
's (thousands) at the start.
I tried generating the template for each trio of characters rather than writing it 3 times, but this was a lot longer.
$endgroup$
$begingroup$
No need for the^
anchor at the beginning;match
already implies it matches at the beginning of the string.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger Thanks, I removed the^
.
$endgroup$
– xnor
yesterday
$begingroup$
Although I think you messed up the count in the edit; should be 83, not 81.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger The count is 81 because thef=
isn't included in the code since anonynomous functions are allowed. It's just for TIO.
$endgroup$
– xnor
yesterday
1
$begingroup$
Ah, makes sense. Annoying there's no way to organize it to hide that in the header or footer, but yeah, unassignedlambda
s are legal, so unassigned bound methods of compiled regex should be good too.
$endgroup$
– ShadowRanger
yesterday
|
show 1 more comment
$begingroup$
Python 2, 81 bytes
import re
re.compile('M,3(D?C,3|C[DM])(L?X,3|X[LC])(V?I,3|I[VX])$').match
Try it online!
Let's look at the last part of the regex, which matching the Roman numerals up to 9 (including the empty string)
V?I,3|I[VX]
This has two alternatives separated by |
:
V?I,3
: An optionalV
followed by up to 3I
's. This matches the empty stringI
,II
,III
,V
,VI
,VII
,VIII
.I[VX]
: AnI
followed by aV
orX
. This matchesIV
andIX
.
The same things with X,L,C
matching the tens, with C,D,M
matches the hundreds, and finally ^M,3
allows up to 3 M
's (thousands) at the start.
I tried generating the template for each trio of characters rather than writing it 3 times, but this was a lot longer.
$endgroup$
$begingroup$
No need for the^
anchor at the beginning;match
already implies it matches at the beginning of the string.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger Thanks, I removed the^
.
$endgroup$
– xnor
yesterday
$begingroup$
Although I think you messed up the count in the edit; should be 83, not 81.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger The count is 81 because thef=
isn't included in the code since anonynomous functions are allowed. It's just for TIO.
$endgroup$
– xnor
yesterday
1
$begingroup$
Ah, makes sense. Annoying there's no way to organize it to hide that in the header or footer, but yeah, unassignedlambda
s are legal, so unassigned bound methods of compiled regex should be good too.
$endgroup$
– ShadowRanger
yesterday
|
show 1 more comment
$begingroup$
Python 2, 81 bytes
import re
re.compile('M,3(D?C,3|C[DM])(L?X,3|X[LC])(V?I,3|I[VX])$').match
Try it online!
Let's look at the last part of the regex, which matching the Roman numerals up to 9 (including the empty string)
V?I,3|I[VX]
This has two alternatives separated by |
:
V?I,3
: An optionalV
followed by up to 3I
's. This matches the empty stringI
,II
,III
,V
,VI
,VII
,VIII
.I[VX]
: AnI
followed by aV
orX
. This matchesIV
andIX
.
The same things with X,L,C
matching the tens, with C,D,M
matches the hundreds, and finally ^M,3
allows up to 3 M
's (thousands) at the start.
I tried generating the template for each trio of characters rather than writing it 3 times, but this was a lot longer.
$endgroup$
Python 2, 81 bytes
import re
re.compile('M,3(D?C,3|C[DM])(L?X,3|X[LC])(V?I,3|I[VX])$').match
Try it online!
Let's look at the last part of the regex, which matching the Roman numerals up to 9 (including the empty string)
V?I,3|I[VX]
This has two alternatives separated by |
:
V?I,3
: An optionalV
followed by up to 3I
's. This matches the empty stringI
,II
,III
,V
,VI
,VII
,VIII
.I[VX]
: AnI
followed by aV
orX
. This matchesIV
andIX
.
The same things with X,L,C
matching the tens, with C,D,M
matches the hundreds, and finally ^M,3
allows up to 3 M
's (thousands) at the start.
I tried generating the template for each trio of characters rather than writing it 3 times, but this was a lot longer.
edited yesterday
answered yesterday
xnorxnor
94k18192451
94k18192451
$begingroup$
No need for the^
anchor at the beginning;match
already implies it matches at the beginning of the string.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger Thanks, I removed the^
.
$endgroup$
– xnor
yesterday
$begingroup$
Although I think you messed up the count in the edit; should be 83, not 81.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger The count is 81 because thef=
isn't included in the code since anonynomous functions are allowed. It's just for TIO.
$endgroup$
– xnor
yesterday
1
$begingroup$
Ah, makes sense. Annoying there's no way to organize it to hide that in the header or footer, but yeah, unassignedlambda
s are legal, so unassigned bound methods of compiled regex should be good too.
$endgroup$
– ShadowRanger
yesterday
|
show 1 more comment
$begingroup$
No need for the^
anchor at the beginning;match
already implies it matches at the beginning of the string.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger Thanks, I removed the^
.
$endgroup$
– xnor
yesterday
$begingroup$
Although I think you messed up the count in the edit; should be 83, not 81.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger The count is 81 because thef=
isn't included in the code since anonynomous functions are allowed. It's just for TIO.
$endgroup$
– xnor
yesterday
1
$begingroup$
Ah, makes sense. Annoying there's no way to organize it to hide that in the header or footer, but yeah, unassignedlambda
s are legal, so unassigned bound methods of compiled regex should be good too.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
No need for the
^
anchor at the beginning; match
already implies it matches at the beginning of the string.$endgroup$
– ShadowRanger
yesterday
$begingroup$
No need for the
^
anchor at the beginning; match
already implies it matches at the beginning of the string.$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger Thanks, I removed the
^
.$endgroup$
– xnor
yesterday
$begingroup$
@ShadowRanger Thanks, I removed the
^
.$endgroup$
– xnor
yesterday
$begingroup$
Although I think you messed up the count in the edit; should be 83, not 81.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
Although I think you messed up the count in the edit; should be 83, not 81.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger The count is 81 because the
f=
isn't included in the code since anonynomous functions are allowed. It's just for TIO.$endgroup$
– xnor
yesterday
$begingroup$
@ShadowRanger The count is 81 because the
f=
isn't included in the code since anonynomous functions are allowed. It's just for TIO.$endgroup$
– xnor
yesterday
1
1
$begingroup$
Ah, makes sense. Annoying there's no way to organize it to hide that in the header or footer, but yeah, unassigned
lambda
s are legal, so unassigned bound methods of compiled regex should be good too.$endgroup$
– ShadowRanger
yesterday
$begingroup$
Ah, makes sense. Annoying there's no way to organize it to hide that in the header or footer, but yeah, unassigned
lambda
s are legal, so unassigned bound methods of compiled regex should be good too.$endgroup$
– ShadowRanger
yesterday
|
show 1 more comment
$begingroup$
Retina, 56 51 bytes
(.)13
0
^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$
Port of @NahuelFouilleul's Perl 5 answer, so make sure to upvote him!
Try it online or verify all test cases.
Explanation:
(.)13 # If four adjacent characters can be found which are the same
0 # Replace it with a 0
^...$ # Then check if the string matches the following fully:
M* # No or any amount of adjacent "M"
( | ) # Followed by either:
C[MD] # A "C" with an "M" or "D" after it
| # or:
D? # An optional "D"
C* # Followed by no or any amount of adjacent "C"
( | ) # Followed by either:
X[CL] # An "X" with a "C" or "L" after it
| # or:
L? # An optional "L"
X* # Followed by no or any amount of adjacent "X"
( | ) # Followed by either:
I[XV] # An "I" with an "X" or "V" after it
| # or:
V? # An optional "V"
I* # Followed by no or any amount of adjacent "I"
$endgroup$
add a comment |
$begingroup$
Retina, 56 51 bytes
(.)13
0
^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$
Port of @NahuelFouilleul's Perl 5 answer, so make sure to upvote him!
Try it online or verify all test cases.
Explanation:
(.)13 # If four adjacent characters can be found which are the same
0 # Replace it with a 0
^...$ # Then check if the string matches the following fully:
M* # No or any amount of adjacent "M"
( | ) # Followed by either:
C[MD] # A "C" with an "M" or "D" after it
| # or:
D? # An optional "D"
C* # Followed by no or any amount of adjacent "C"
( | ) # Followed by either:
X[CL] # An "X" with a "C" or "L" after it
| # or:
L? # An optional "L"
X* # Followed by no or any amount of adjacent "X"
( | ) # Followed by either:
I[XV] # An "I" with an "X" or "V" after it
| # or:
V? # An optional "V"
I* # Followed by no or any amount of adjacent "I"
$endgroup$
add a comment |
$begingroup$
Retina, 56 51 bytes
(.)13
0
^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$
Port of @NahuelFouilleul's Perl 5 answer, so make sure to upvote him!
Try it online or verify all test cases.
Explanation:
(.)13 # If four adjacent characters can be found which are the same
0 # Replace it with a 0
^...$ # Then check if the string matches the following fully:
M* # No or any amount of adjacent "M"
( | ) # Followed by either:
C[MD] # A "C" with an "M" or "D" after it
| # or:
D? # An optional "D"
C* # Followed by no or any amount of adjacent "C"
( | ) # Followed by either:
X[CL] # An "X" with a "C" or "L" after it
| # or:
L? # An optional "L"
X* # Followed by no or any amount of adjacent "X"
( | ) # Followed by either:
I[XV] # An "I" with an "X" or "V" after it
| # or:
V? # An optional "V"
I* # Followed by no or any amount of adjacent "I"
$endgroup$
Retina, 56 51 bytes
(.)13
0
^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$
Port of @NahuelFouilleul's Perl 5 answer, so make sure to upvote him!
Try it online or verify all test cases.
Explanation:
(.)13 # If four adjacent characters can be found which are the same
0 # Replace it with a 0
^...$ # Then check if the string matches the following fully:
M* # No or any amount of adjacent "M"
( | ) # Followed by either:
C[MD] # A "C" with an "M" or "D" after it
| # or:
D? # An optional "D"
C* # Followed by no or any amount of adjacent "C"
( | ) # Followed by either:
X[CL] # An "X" with a "C" or "L" after it
| # or:
L? # An optional "L"
X* # Followed by no or any amount of adjacent "X"
( | ) # Followed by either:
I[XV] # An "I" with an "X" or "V" after it
| # or:
V? # An optional "V"
I* # Followed by no or any amount of adjacent "I"
edited 21 hours ago
answered 21 hours ago
Kevin CruijssenKevin Cruijssen
42.7k571217
42.7k571217
add a comment |
add a comment |
$begingroup$
05AB1E, 61 bytes
•1∞Γ'иÛnuÞ₂…•Ž8вв€SÐ)v.•6#&‘нδ•u3ôNèyè}'M3L×)Rεõš}`3Fâ}€˜JIå
Try it online or verify all test cases.
Explanation:
•1∞Γ'иÛnuÞ₂…• '# Push compressed integer 397940501547566186191992778
Ž8в # Push compressed integer 2112
в # Convert the integer to Base-2112 as list:
# [1,11,111,12,2,21,211,2111,10]
€S # Convert each number to a list of digits
Ð # Triplicate this list
) # And wrap it into a list of lists (of lists)
v # Loop `y` over each these three lists:
.•6#&‘нδ• # Push compressed string "xivcxlmcd"
u # Uppercased
3ô # And split into parts of size 3: ["XIV","CXL","MCD"]
Nè # Use the loop index to get the current part
yè # And index the list of lists of digits into this string
}'M '# After the loop: push "M"
3L # Push list [1,2,3]
× # Repeat the "M" that many times: ["M","MM","MMM"]
) # Wrap all lists on the stack into a list:
# [[["I"],["I","I"],["I","I","I"],["I","V"],["V"],["V","I"],["V","I","I"],["V","I","I","I"],["I","X"]],[["X"],["X","X"],["X","X","X"],["X","L"],["L"],["L","X"],["L","X","X"],["L","X","X","X"],["X","C"]],[["C"],["C","C"],["C","C","C"],["C","D"],["D"],["D","C"],["D","C","C"],["D","C","C","C"],["C","M"]],["M","MM","MMM"]]
R # Reverse this list
εõš} # Prepend an empty string "" before each inner list
` # Push the four lists onto the stack
3F # Loop 3 times:
â # Take the cartesian product of the two top lists
}€˜ # After the loop: flatten each inner list
J # Join each inner list together to a single string
Iå # And check if the input is in this list
# (after which the result is output implicitly)
See this 05AB1E tip of mine (sections How to compress strings not part of the dictionary?, How to compress large integers?, and How to compress integer lists?) to understand why:
•1∞Γ'иÛnuÞ₂…•
is397940501547566186191992778
Ž8в
is2112
•1∞Γ'иÛnuÞ₂…•Ž8вв
is[1,11,111,12,2,21,211,2111,10]
.•6#&‘нδ•
is"xivcxlmcd"
$endgroup$
add a comment |
$begingroup$
05AB1E, 61 bytes
•1∞Γ'иÛnuÞ₂…•Ž8вв€SÐ)v.•6#&‘нδ•u3ôNèyè}'M3L×)Rεõš}`3Fâ}€˜JIå
Try it online or verify all test cases.
Explanation:
•1∞Γ'иÛnuÞ₂…• '# Push compressed integer 397940501547566186191992778
Ž8в # Push compressed integer 2112
в # Convert the integer to Base-2112 as list:
# [1,11,111,12,2,21,211,2111,10]
€S # Convert each number to a list of digits
Ð # Triplicate this list
) # And wrap it into a list of lists (of lists)
v # Loop `y` over each these three lists:
.•6#&‘нδ• # Push compressed string "xivcxlmcd"
u # Uppercased
3ô # And split into parts of size 3: ["XIV","CXL","MCD"]
Nè # Use the loop index to get the current part
yè # And index the list of lists of digits into this string
}'M '# After the loop: push "M"
3L # Push list [1,2,3]
× # Repeat the "M" that many times: ["M","MM","MMM"]
) # Wrap all lists on the stack into a list:
# [[["I"],["I","I"],["I","I","I"],["I","V"],["V"],["V","I"],["V","I","I"],["V","I","I","I"],["I","X"]],[["X"],["X","X"],["X","X","X"],["X","L"],["L"],["L","X"],["L","X","X"],["L","X","X","X"],["X","C"]],[["C"],["C","C"],["C","C","C"],["C","D"],["D"],["D","C"],["D","C","C"],["D","C","C","C"],["C","M"]],["M","MM","MMM"]]
R # Reverse this list
εõš} # Prepend an empty string "" before each inner list
` # Push the four lists onto the stack
3F # Loop 3 times:
â # Take the cartesian product of the two top lists
}€˜ # After the loop: flatten each inner list
J # Join each inner list together to a single string
Iå # And check if the input is in this list
# (after which the result is output implicitly)
See this 05AB1E tip of mine (sections How to compress strings not part of the dictionary?, How to compress large integers?, and How to compress integer lists?) to understand why:
•1∞Γ'иÛnuÞ₂…•
is397940501547566186191992778
Ž8в
is2112
•1∞Γ'иÛnuÞ₂…•Ž8вв
is[1,11,111,12,2,21,211,2111,10]
.•6#&‘нδ•
is"xivcxlmcd"
$endgroup$
add a comment |
$begingroup$
05AB1E, 61 bytes
•1∞Γ'иÛnuÞ₂…•Ž8вв€SÐ)v.•6#&‘нδ•u3ôNèyè}'M3L×)Rεõš}`3Fâ}€˜JIå
Try it online or verify all test cases.
Explanation:
•1∞Γ'иÛnuÞ₂…• '# Push compressed integer 397940501547566186191992778
Ž8в # Push compressed integer 2112
в # Convert the integer to Base-2112 as list:
# [1,11,111,12,2,21,211,2111,10]
€S # Convert each number to a list of digits
Ð # Triplicate this list
) # And wrap it into a list of lists (of lists)
v # Loop `y` over each these three lists:
.•6#&‘нδ• # Push compressed string "xivcxlmcd"
u # Uppercased
3ô # And split into parts of size 3: ["XIV","CXL","MCD"]
Nè # Use the loop index to get the current part
yè # And index the list of lists of digits into this string
}'M '# After the loop: push "M"
3L # Push list [1,2,3]
× # Repeat the "M" that many times: ["M","MM","MMM"]
) # Wrap all lists on the stack into a list:
# [[["I"],["I","I"],["I","I","I"],["I","V"],["V"],["V","I"],["V","I","I"],["V","I","I","I"],["I","X"]],[["X"],["X","X"],["X","X","X"],["X","L"],["L"],["L","X"],["L","X","X"],["L","X","X","X"],["X","C"]],[["C"],["C","C"],["C","C","C"],["C","D"],["D"],["D","C"],["D","C","C"],["D","C","C","C"],["C","M"]],["M","MM","MMM"]]
R # Reverse this list
εõš} # Prepend an empty string "" before each inner list
` # Push the four lists onto the stack
3F # Loop 3 times:
â # Take the cartesian product of the two top lists
}€˜ # After the loop: flatten each inner list
J # Join each inner list together to a single string
Iå # And check if the input is in this list
# (after which the result is output implicitly)
See this 05AB1E tip of mine (sections How to compress strings not part of the dictionary?, How to compress large integers?, and How to compress integer lists?) to understand why:
•1∞Γ'иÛnuÞ₂…•
is397940501547566186191992778
Ž8в
is2112
•1∞Γ'иÛnuÞ₂…•Ž8вв
is[1,11,111,12,2,21,211,2111,10]
.•6#&‘нδ•
is"xivcxlmcd"
$endgroup$
05AB1E, 61 bytes
•1∞Γ'иÛnuÞ₂…•Ž8вв€SÐ)v.•6#&‘нδ•u3ôNèyè}'M3L×)Rεõš}`3Fâ}€˜JIå
Try it online or verify all test cases.
Explanation:
•1∞Γ'иÛnuÞ₂…• '# Push compressed integer 397940501547566186191992778
Ž8в # Push compressed integer 2112
в # Convert the integer to Base-2112 as list:
# [1,11,111,12,2,21,211,2111,10]
€S # Convert each number to a list of digits
Ð # Triplicate this list
) # And wrap it into a list of lists (of lists)
v # Loop `y` over each these three lists:
.•6#&‘нδ• # Push compressed string "xivcxlmcd"
u # Uppercased
3ô # And split into parts of size 3: ["XIV","CXL","MCD"]
Nè # Use the loop index to get the current part
yè # And index the list of lists of digits into this string
}'M '# After the loop: push "M"
3L # Push list [1,2,3]
× # Repeat the "M" that many times: ["M","MM","MMM"]
) # Wrap all lists on the stack into a list:
# [[["I"],["I","I"],["I","I","I"],["I","V"],["V"],["V","I"],["V","I","I"],["V","I","I","I"],["I","X"]],[["X"],["X","X"],["X","X","X"],["X","L"],["L"],["L","X"],["L","X","X"],["L","X","X","X"],["X","C"]],[["C"],["C","C"],["C","C","C"],["C","D"],["D"],["D","C"],["D","C","C"],["D","C","C","C"],["C","M"]],["M","MM","MMM"]]
R # Reverse this list
εõš} # Prepend an empty string "" before each inner list
` # Push the four lists onto the stack
3F # Loop 3 times:
â # Take the cartesian product of the two top lists
}€˜ # After the loop: flatten each inner list
J # Join each inner list together to a single string
Iå # And check if the input is in this list
# (after which the result is output implicitly)
See this 05AB1E tip of mine (sections How to compress strings not part of the dictionary?, How to compress large integers?, and How to compress integer lists?) to understand why:
•1∞Γ'иÛnuÞ₂…•
is397940501547566186191992778
Ž8в
is2112
•1∞Γ'иÛnuÞ₂…•Ž8вв
is[1,11,111,12,2,21,211,2111,10]
.•6#&‘нδ•
is"xivcxlmcd"
edited 23 hours ago
answered yesterday
Kevin CruijssenKevin Cruijssen
42.7k571217
42.7k571217
add a comment |
add a comment |
$begingroup$
perl -MRegexp::Common -pe, 34 bytes
$_=/^$REnumroman$/&!/(.)13/
The &!/(.)13/
part is necessary, because Regexp::Common
allows four (but not five) of the same characters in a row. That way, it matches roman numbers used on clock faces, where IIII
is often used for 4.
$endgroup$
add a comment |
$begingroup$
perl -MRegexp::Common -pe, 34 bytes
$_=/^$REnumroman$/&!/(.)13/
The &!/(.)13/
part is necessary, because Regexp::Common
allows four (but not five) of the same characters in a row. That way, it matches roman numbers used on clock faces, where IIII
is often used for 4.
$endgroup$
add a comment |
$begingroup$
perl -MRegexp::Common -pe, 34 bytes
$_=/^$REnumroman$/&!/(.)13/
The &!/(.)13/
part is necessary, because Regexp::Common
allows four (but not five) of the same characters in a row. That way, it matches roman numbers used on clock faces, where IIII
is often used for 4.
$endgroup$
perl -MRegexp::Common -pe, 34 bytes
$_=/^$REnumroman$/&!/(.)13/
The &!/(.)13/
part is necessary, because Regexp::Common
allows four (but not five) of the same characters in a row. That way, it matches roman numbers used on clock faces, where IIII
is often used for 4.
answered 15 hours ago
AbigailAbigail
45617
45617
add a comment |
add a comment |
$begingroup$
Python 3, 116 113 109 107 105 106 bytes
import re
lambda n:re.match(r'(M,3(C(M|CC?|D)?|DC,3))(X(C|XX?|L)?|(LX,3))?(I(X|II?|V)?|VI,3)?$',n)
Try it online!
-1 byte thanks to ShadowRanger
$endgroup$
2
$begingroup$
As I mentioned on the Py2 answer, the leading^
is unnecessary sincematch
only matches at the beginning of a string already.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger added anchors while debugging and then didn't try again without them. I'll remember that now - thanks! :)
$endgroup$
– Noodle9
16 hours ago
$begingroup$
Well, just to be clear, the trailing$
is necessary (onlyfullmatch
implies anchors on both ends, and obviously that would cost more than a$
).
$endgroup$
– ShadowRanger
15 hours ago
$begingroup$
@ShadowRanger Ah! That explains why I needed anchors! Didn't realize I only needed to anchor the end. Thanks again.
$endgroup$
– Noodle9
15 hours ago
add a comment |
$begingroup$
Python 3, 116 113 109 107 105 106 bytes
import re
lambda n:re.match(r'(M,3(C(M|CC?|D)?|DC,3))(X(C|XX?|L)?|(LX,3))?(I(X|II?|V)?|VI,3)?$',n)
Try it online!
-1 byte thanks to ShadowRanger
$endgroup$
2
$begingroup$
As I mentioned on the Py2 answer, the leading^
is unnecessary sincematch
only matches at the beginning of a string already.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger added anchors while debugging and then didn't try again without them. I'll remember that now - thanks! :)
$endgroup$
– Noodle9
16 hours ago
$begingroup$
Well, just to be clear, the trailing$
is necessary (onlyfullmatch
implies anchors on both ends, and obviously that would cost more than a$
).
$endgroup$
– ShadowRanger
15 hours ago
$begingroup$
@ShadowRanger Ah! That explains why I needed anchors! Didn't realize I only needed to anchor the end. Thanks again.
$endgroup$
– Noodle9
15 hours ago
add a comment |
$begingroup$
Python 3, 116 113 109 107 105 106 bytes
import re
lambda n:re.match(r'(M,3(C(M|CC?|D)?|DC,3))(X(C|XX?|L)?|(LX,3))?(I(X|II?|V)?|VI,3)?$',n)
Try it online!
-1 byte thanks to ShadowRanger
$endgroup$
Python 3, 116 113 109 107 105 106 bytes
import re
lambda n:re.match(r'(M,3(C(M|CC?|D)?|DC,3))(X(C|XX?|L)?|(LX,3))?(I(X|II?|V)?|VI,3)?$',n)
Try it online!
-1 byte thanks to ShadowRanger
edited 15 hours ago
answered yesterday
Noodle9Noodle9
30137
30137
2
$begingroup$
As I mentioned on the Py2 answer, the leading^
is unnecessary sincematch
only matches at the beginning of a string already.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger added anchors while debugging and then didn't try again without them. I'll remember that now - thanks! :)
$endgroup$
– Noodle9
16 hours ago
$begingroup$
Well, just to be clear, the trailing$
is necessary (onlyfullmatch
implies anchors on both ends, and obviously that would cost more than a$
).
$endgroup$
– ShadowRanger
15 hours ago
$begingroup$
@ShadowRanger Ah! That explains why I needed anchors! Didn't realize I only needed to anchor the end. Thanks again.
$endgroup$
– Noodle9
15 hours ago
add a comment |
2
$begingroup$
As I mentioned on the Py2 answer, the leading^
is unnecessary sincematch
only matches at the beginning of a string already.
$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger added anchors while debugging and then didn't try again without them. I'll remember that now - thanks! :)
$endgroup$
– Noodle9
16 hours ago
$begingroup$
Well, just to be clear, the trailing$
is necessary (onlyfullmatch
implies anchors on both ends, and obviously that would cost more than a$
).
$endgroup$
– ShadowRanger
15 hours ago
$begingroup$
@ShadowRanger Ah! That explains why I needed anchors! Didn't realize I only needed to anchor the end. Thanks again.
$endgroup$
– Noodle9
15 hours ago
2
2
$begingroup$
As I mentioned on the Py2 answer, the leading
^
is unnecessary since match
only matches at the beginning of a string already.$endgroup$
– ShadowRanger
yesterday
$begingroup$
As I mentioned on the Py2 answer, the leading
^
is unnecessary since match
only matches at the beginning of a string already.$endgroup$
– ShadowRanger
yesterday
$begingroup$
@ShadowRanger added anchors while debugging and then didn't try again without them. I'll remember that now - thanks! :)
$endgroup$
– Noodle9
16 hours ago
$begingroup$
@ShadowRanger added anchors while debugging and then didn't try again without them. I'll remember that now - thanks! :)
$endgroup$
– Noodle9
16 hours ago
$begingroup$
Well, just to be clear, the trailing
$
is necessary (only fullmatch
implies anchors on both ends, and obviously that would cost more than a $
).$endgroup$
– ShadowRanger
15 hours ago
$begingroup$
Well, just to be clear, the trailing
$
is necessary (only fullmatch
implies anchors on both ends, and obviously that would cost more than a $
).$endgroup$
– ShadowRanger
15 hours ago
$begingroup$
@ShadowRanger Ah! That explains why I needed anchors! Didn't realize I only needed to anchor the end. Thanks again.
$endgroup$
– Noodle9
15 hours ago
$begingroup$
@ShadowRanger Ah! That explains why I needed anchors! Didn't realize I only needed to anchor the end. Thanks again.
$endgroup$
– Noodle9
15 hours ago
add a comment |
$begingroup$
Ruby, (-n
) 56 bytes
p~/^M,3(D?C,3|CM|CD)(L?X,3|XC|XL)(V?I,3|IV|IX)$/
Try it online!
Outputs 0 (truthy) or nil (falsy).
$endgroup$
add a comment |
$begingroup$
Ruby, (-n
) 56 bytes
p~/^M,3(D?C,3|CM|CD)(L?X,3|XC|XL)(V?I,3|IV|IX)$/
Try it online!
Outputs 0 (truthy) or nil (falsy).
$endgroup$
add a comment |
$begingroup$
Ruby, (-n
) 56 bytes
p~/^M,3(D?C,3|CM|CD)(L?X,3|XC|XL)(V?I,3|IV|IX)$/
Try it online!
Outputs 0 (truthy) or nil (falsy).
$endgroup$
Ruby, (-n
) 56 bytes
p~/^M,3(D?C,3|CM|CD)(L?X,3|XC|XL)(V?I,3|IV|IX)$/
Try it online!
Outputs 0 (truthy) or nil (falsy).
answered 13 hours ago
iamnotmaynardiamnotmaynard
95349
95349
add a comment |
add a comment |
If this is an answer to a challenge…
…Be sure to follow the challenge specification. However, please refrain from exploiting obvious loopholes. Answers abusing any of the standard loopholes are considered invalid. If you think a specification is unclear or underspecified, comment on the question instead.
…Try to optimize your score. For instance, answers to code-golf challenges should attempt to be as short as possible. You can always include a readable version of the code in addition to the competitive one.
Explanations of your answer make it more interesting to read and are very much encouraged.…Include a short header which indicates the language(s) of your code and its score, as defined by the challenge.
More generally…
…Please make sure to answer the question and provide sufficient detail.
…Avoid asking for help, clarification or responding to other answers (use comments instead).
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodegolf.stackexchange.com%2fquestions%2f183014%2fmatch-roman-numerals%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
-code-golf, decision-problem, number, roman-numerals, string
$begingroup$
Subset of this conversion challenge.
$endgroup$
– Shaggy
yesterday
$begingroup$
I still don't think this qualifies as a "subset" as the set of invalid inputs is larger. This challenge here only refers to the "well"-defined numbers that are used in OEIS A006968
$endgroup$
– flawr
yesterday
$begingroup$
Why is
MMMM
invalid? Is there a letter for 5000 that should be used instead for M<letter>?$endgroup$
– Skyler
15 hours ago
$begingroup$
Check out the specs, there is no such letter. The only symbols used are
I,V,X,L,C,D,M
.$endgroup$
– flawr
14 hours ago