[Question]
  [
### 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](https://oeis.org/A006968/a006968.txt)
### Examples
**Truthy**
```
MCCXXXIV (1234)
CMLXXXVIII (988)
DXIV (514)
CI (101)
```
**Falsey**
```
MMIXVIII
IVX
IXV
MMMM
XXXVX
IVI
VIV
```
  
[Answer]
# [Verbose](https://esolangs.org/wiki/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.
[Answer]
## [C# (Visual C# Interactive Compiler)](https://www.mono-project.com/docs/about-mono/releases/5.0.0/#csc), ~~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,"^M{0,3}(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$")
```
[Try it online!](https://tio.run/##dY5NC4JAEIbv/YqQDiuYBB378LAWDDiXim1BDEo2WzANZwMj@@32eYm24/O8M@9MSv2UdDs/F@mYTKWLzNuVZT7t7ruTlibT5YWMOvorVRt/obJzvq1m9alSRLos6KlU7QPh1qQHRp6zwevAG94YjzFMmjDgL3SZjHmUNFEgPwyxFEkjAnhzz3HbdaWNinSh2J45yLmUEoTjuqPOV8IxeiQCAH6z0L5hmUSEPx0gpEVKYetA/LXP52wN4nWrvQM)
[Answer]
# Java 8, 70 bytes
```
s->s.matches("M{0,3}(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})")
```
Port of [*@Innat3*'s C# answer](https://codegolf.stackexchange.com/a/183016/52210), so make sure to upvote him!
[Try it online.](https://tio.run/##jZBBa4MwHMXvfoo/nhRWO9htZfMQGQRMLx0hIB7SNFvtNBYTC6X62V20jp1KzCHwyOO938uJX/jqdPgZRMm1BsILdfMACmVk88WFhO0oAfZ1XUquQAQ70xTqG3S4sQ@9Zy9tuCkEbEHBGwx69a6jihtxlDrwye356aUPUEaSvEtiNMkwYBlK8y6N2axxxmje0RjftR8OmzH53O5LmzwXXOriAJUlnBmyHHh4x1uv4bNpzfH6OsndVRtZRXVrorN1mlIFKhKWBiHGGKZ@ONE/NiKSWiPFGDutizOTRcX/hXbTBy@1fLzJRUbwsgmYMreHueGJPU7T@K8L6ugfdu/1wy8)
**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 "$")
M{0,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"
         C{0,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"
         X{0,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"
         I{0,3}    //  Followed by no, 1, 2, or 3 adjacent "I"
```
[Answer]
# [Wolfram Language (Mathematica)](https://www.wolfram.com/wolframscript/), 35 bytes
```
Check[FromRomanNumeral@#<3999,1<0]&
```
[Try it online!](https://tio.run/##y00syUjNTSzJTE78n2773zkjNTk72q0oPzcoPzcxz680N7UoMcdB2cbY0tJSx9DGIFbtf0BRZl6Jgr5DYGlmakl0ur6DQrWSr7NzRESEZ5iSjpKzrw@QGebp6QnkuEDFQGxfX0@YsGdYBIiMCAML@/oCKZAesGCYp1Jt7P//AA "Wolfram Language (Mathematica) – 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)](https://www.wolfram.com/wolframscript/), 28 bytes
```
Check[FromRomanNumeral@#,F]&
```
[Try it online!](https://tio.run/##y00syUjNTSzJTE78n2773zkjNTk72q0oPzcoPzcxz680N7UoMcdBWcctVu1/QFFmXomCvkNgaWZqSXS6voNCtZKvs3NERIRnmJKOkrOvD5AZ5unpCeS4QMVAbF9fT5iwZ1gEiIwIAwv7@gIpkB6wYJinUm3s//8A "Wolfram Language (Mathematica) – Try It Online")
the above code works for any number, not just [1,3999]
[Answer]
# [CP-1610](https://en.wikipedia.org/wiki/General_Instrument_CP1600) assembly ([Intellivision](https://en.wikipedia.org/wiki/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[##]|#?M{0,3})(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,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 \$(\text{main\_digit}, \text{second\_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
[![output](https://i.stack.imgur.com/j8byw.gif)](https://i.stack.imgur.com/j8byw.gif)
*screenshot of [jzIntv](http://spatula-city.org/~im14u2c/intv/)*
---
*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).*
[Answer]
# [R](https://www.r-project.org/), ~~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!](https://tio.run/##JYoxCwIxDEb3/IzAQYPl4NzqGpeAWUuGQ6ji4OAp1/P31/Tc3nvft7ZWv7eAVw3jgTDiPE8Y670sISISDc9l@JS6PUKp4/p@eZ9Ox5QSUVNmM5MMrBeHLCJw3l1AVf5BsoGjB1XoL9fcd2U1FgN17ro/2g8 "R – Try It Online")
[Answer]
# [Wolfram Language (Mathematica)](https://www.wolfram.com/wolframscript/), 32 bytes
```
RomanNumeral@Range@3999~Count~#&
```
[Try it online!](https://tio.run/##y00syUjNTSzJTE78n277Pyg/NzHPrzQ3tSgxxyEoMS891cHY0tKyzjm/NK@kTlntf0BRZl6Jgr5DYGlmakl0ur6DQrWSr7NzRESEZ5iSjpKzrw@QGebp6QnkuEDFQGxfX0@YsGdYBIiMCAML@/oCKZAesGCYp1Jt7P//AA "Wolfram Language (Mathematica) – Try It Online")
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~48 47 46~~ 44 [bytes](https://github.com/DennisMitchell/jelly/wiki/Code-page)
-1 thanks to Nick Kennedy
```
5Żo7;“ÆæC‘ð“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!](https://tio.run/##y0rNyan8/9/06O58c@tHDXMOtx1e5vyoYUaS8eENQK5nWISPs4vvo4a5D3d3OxgfW5JrBGT7PtzV/WjjOuNDSx7uXHt096OmNQ93zjo6qcANxNoxH0gaHOn@//@/s69PREREmKenJwA "Jelly – Try It Online")** Or see the [test-suite](https://tio.run/##y0rNyan8/9/06O58c@tHDXMOtx1e5vyoYUaS8eENQK5nWISPs4vvo4a5D3d3OxgfW5JrBGT7PtzV/WjjOuNDSx7uXHt096OmNQ93zjo6qcANxNoxH0gaHOn@f7gdyPj/P1rd19k5IiLCM0xdh0tB3dnXB8gJ8/T0BHNd4OIQvq@vJ0ISaDuEjgiDSvr6ghkgE6BSYSClsQA "Jelly – Try It Online").
### How?
```
5Żo7;“ÆæC‘ð“IVXLCDM”ṃ@3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ  - Main Link: list of characters S
5Żo7;“ÆæC‘  - chain 1: f(S) -> X
5Ż          - zero range of five = [0,1,2,3,4,5]
  o7        - OR seven             [7,1,2,3,4,5]
     “ÆæC‘  - list of code-page indices        [13,22,67]
    ;       - concatenate          [7,1,2,3,4,5,13,22,67]
          ð - start a new dyadic chain...
“IVXLCDM”ṃ@3Ƥm2”MẋⱮ3¤ṭŻ€ṚŒpF€ḟ€0ċ - chain 2: f(X,S) -> isValid
“IVXLCDM”                         - list of characters, IVXLCDM
           3Ƥ                     - for infixes of length three:
                                  - (i.e. IVX VXL XLC LCD CDM)
         ṃ@                       -   base decompression with swapped arguments
                                  -   (i.e. use characters as base-3 digits of X's values)
                                  -   (e.g. IVX -> VI I V IX II IV III VII VIII)
             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 DC C D CM CC CD CCC DCC DCCC
                                  -    0 LX X L XC XX XL XXX LXX LXXX
                                  -    0 VI I V IX II IV III VII VIII
                         Œp       - Cartesian product   [[0,0,0,0],...,["M","CM",0,"IV"],...]
                           F€     - flatten €ach  [[0,0,0,0],...,['M','C','M',0,'I','V'],...]
                             ḟ€0  - filter out the zeros from €ach       ["",...,"MCMIV",...]
                                ċ - count occurrences of S
```
[Answer]
# Perl 5 (`-p`), 57 bytes
```
$_=/^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$/&!/(.)\1{3}/
```
[TIO](https://tio.run/##HYu9CsIwFEb3PEWFIknAXmMtVEQ6pMuF3jVcqKmTg1BssW7WVzem3c75fsb7qy/CBEmmAc4hvV2gIy1tS7Wf68pqJbm1jZ@biiNjy87PrkKtUthuQGbqaj75F0Iga5kZXSLNIT8qYamJ7hAxkaeyVKJey8IsXczM3ihBhOtEoGMRMQZEYvlFdfgbxvdjeE5h149/)
* uses almost the same regular expression except `{0,3}` quantifier was changed by `*`
* `&!/(.)\1{3}/` to ensure the same character can't occur 4 times in a row.
* can't be golfed with `-/(.)\1{3}/` because would give`-1` for `IIIIVI` for example
[Answer]
# [Python 2](https://docs.python.org/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!](https://tio.run/##JczBCoMwDAbge5/Cw8AWhrDtNhge6iVgriUgMpwoFqwtpUPGtmfvqssl//cT4l5hsss5Rm2c9SHzAxtvfih6a5yeB57j@3j58qqU2/7IpsJW8LqkndTUMlGVsBMaRa045KIwXeinuE7pRXa6Oq@XwB/WznzkvlvvenHPwEWaiFISESgmsU5BAQCrdgNDhH8BiliKqUBk21WigvgD "Python 2 – 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 optional `V` followed by up to 3 `I`'s. This matches the empty string `I`,`II`,`III`, `V`, `VI`,`VII`,`VIII`.
* `I[VX]`: An `I` followed by a `V` or `X`. This matches `IV` and `IX`.
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.
[Answer]
# [Retina](https://github.com/m-ender/retina/wiki/The-Language), ~~56~~ 51 bytes
```
(.)\1{3}
0
^M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$
```
Port of [*@NahuelFouilleul*'s Perl 5 answer](https://codegolf.stackexchange.com/a/183023/52210), so make sure to upvote him!
[Try it online](https://tio.run/##K0otycxLNPz/X0NPM8aw2riWy4ArzldLwzna1yW2xsXeWUtTIyLa2Se2xsc@Asj2jI4Ii60Js/fU0lT5/9/X19fZN8LZMwIA) or [verify all test cases](https://tio.run/##JYqxCgIxEAX7/Q6FJIV4@AEpNiAP8tpl4YxoYWFjIXbefXuM2s0M87y97o/r1LfheOlhF0/T@7DKXs5MQWeWtpSsKQaftbalZh@M2a0tlpHipneSSle4UNXdYaKsAwyAlJ9DSPwDzGXgCKR8r6EGMdgH).
**Explanation:**
```
(.)\1{3}        # 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"
```
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E/wiki/Commands), ~~61~~ ~~9~~ 8 [bytes](https://github.com/Adriandmen/05AB1E/wiki/Codepage)
```
ŽF¯L.XIå
```
Whopping \$\color{green}{\textrm{-52 bytes}}\$ thanks to *@Adnan*, because apparently 05AB1E's Roman Number builtin wasn't documented, haha.. xD
[Try it online](https://tio.run/##yy9OTMpM/f//6F63Q@t99CI8Dy/9/9/X19fZN8LZMwIA) or [verify all test cases](https://tio.run/##yy9OTMpM/V9Waa@k8KhtkoKS/f@je90OrffRi6g8vPS/zv9oJV9fX2ffCGfPCCUdJV9n54iICM8wINPZ1wfIDPP09ARyXKBiQLYCUIMnTNwzDKQLyAXpBQIgBdIEFgzzVIoFAA).
**Explanation:**
```
ŽF¯       # Push comressed integer 3999
   L      # Create a list in the range [1,3999]
    .X    # Convert each integer in this list to a roman number string
      Iå  # Check if the input is in this list
          # (and output the result implicitly)
```
[See this 05AB1E tip of mine (section *How to compress large integers?*)](https://codegolf.stackexchange.com/a/166851/52210) to understand why `ŽF¯` is `3999`.
---
**Original 61 bytes answer:**
```
•1∞Γ'иÛnuÞ\₂…•Ž8вв€SÐ)v.•6#&‘нδ•u3ôNèyè}'M3L×)Rεõš}`3Fâ}€˜JIå
```
[Try it online](https://tio.run/##AXgAh/9vc2FiaWX//@KAojHiiJ7OkyfQuMObbnXDnlzigoLigKbigKLFvTjQstCy4oKsU8OQKXYu4oCiNiMm4oCY0L3OtOKAonUzw7ROw6h5w6h9J00zTMOXKVLOtcO1xaF9YDNGw6J94oKsy5xKScOl//9NTU1DTVhDSVg) or [verify all test cases](https://tio.run/##yy9OTMpM/V9Waa@k8KhtkoKS/f9HDYsMH3XMOzdZ/cKOw7PzSg/Pi3nU1PSoYRlQ4uheiwubLmx61LQm@PAEzTI9oJCZstqjhhkX9p7bAuSUGh/e4nd4ReXhFbXqvsY@h6drBp3benjr0YW1CcZuhxfVAjWenuNVeXjpf53/0Uq@vr7OvhHOnhFKOkq@zs4RERGeYUCms68PkBnm6ekJ5LhAxYBsBaAGT5i4ZxhIF5AL0gsEQAqkCSwY5qkUCwA).
**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?*)](https://codegolf.stackexchange.com/a/166851/52210) to understand why:
* `•1∞Γ'иÛnuÞ\₂…•` is `397940501547566186191992778`
* `Ž8в` is `2112`
* `•1∞Γ'иÛnuÞ\₂…•Ž8вв` is `[1,11,111,12,2,21,211,2111,10]`
* `.•6#&‘нδ•` is `"xivcxlmcd"`
[Answer]
# perl -MRegexp::Common -pe, 34 bytes
```
$_=/^$RE{num}{roman}$/&!/(.)\1{3}/
```
The `&!/(.)\1{3}/` 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. 
[Answer]
# [Python 3](https://docs.python.org/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!](https://tio.run/##K6gsycjPM/6fbvs/M7cgv6hEoSiVKycxNyklUSHPqihVLzexJDlDo0hdw7dax7hWw1nDt8bZ2b7GRROInUFCmpoaERrONRER9jU@QEENnwiIqL2Gp0ZEjaenfU0YUDjMEyxqr6Kuk6f5//9/AA "Python 3 – Try It Online")
*-1 byte thanks to ShadowRanger*
[Answer]
# [Ruby](https://www.ruby-lang.org/), (`-n`) 56 bytes
```
p~/^M{,3}(D?C{,3}|CM|CD)(L?X{,3}|XC|XL)(V?I{,3}|IV|IX)$/
```
[Try it online!](https://tio.run/##JYq7CgIxEEX7@Q6LBJQt7Gy2mDQXdtphKkELUZDdZR/FYvTTjUms7jmHO63XLaXx05zltT@@XWi5bGSJHLzrWqtqHK3zTltUhUaY3zUpLdO63LcTCbOZQYmly6AAKFQH3S7PuVwE/w41ypiDCJVzVgUp9DuMy2Po53Tofw "Ruby – Try It Online")
Outputs 0 (truthy) or nil (falsy).
]