Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Challenges

Post History

60%
+1 −0
Challenges The 50 substrings that validate any string of Roman numerals

Python, 205 bytes Coding the string with the substrings as base 95 number is the shortest I get with this approach: n=0 for c in"),|9'OJ#SdHlCSD(LqRhc.|)_#s]`N:?foSIb*.BJVa=AH^).&&w*e(&l...

posted 6mo ago by __blackjack__‭  ·  edited 6mo ago by __blackjack__‭

Answer
#2: Post edited by user avatar __blackjack__‭ · 2026-03-08T16:57:46Z (6 months ago)
One byte less.
  • # Python, 206 bytes
  • Arpad Horvath's packing two six bit characters into one ASCII character could make the 209 byte solution even better, so this builds on his work. The unpacking is a bit shorter and the final function works different and is also a bit shorter.
  • ```
  • n=" IVXLCDM"
  • x="".join(n[(d:=ord(c)-32)>>3]+n[d&7]for c in'&PW!H.!@/$HF$@G"H6"@7"03#P?%N%O%U%]%^%_&N&O!*!+!1!=!9!<!:!;$=$<"*"+#M#N#L#O#K#C#=#<%MH))\'_X;;')
  • f=lambda s:next((a for a in x.split()if a in s),1)
  • ```
  • [Try it online!](https://tio.run/##TY1BT4NAEIXv/IrdWRZ2S0UriVXoVhKMQixtL9ZNKjZYJGLahVBM6q9HaC9@l3nzJvNe9dt8lcq5req2VQJQtJKz4CEG7SgA7O@yUEytWeaKss7Yll8413w6dRJLrTNjnORljbaoUKaxfMWhjf1LPXzU/ScIb8Afw5VDlvd0Thf0hSb0nW6MubHAA2zhERb4Dk@wiz1d6BMYgEViMiczsiDPJCCCTGgccv5mbqTnmVzLxS7df2QpOrjq89gwlqK@PO3K0dE@VLuiYbzIz8aBD0e87e/qZ98ba4hWMEQQBx1yFZ10xyzoVdRxdqT8L08vMj7tUgaQuBpCqKoL1bAueIjyfnDe/gE "Python 3.8 (pre-release) – Try It Online")
  • # 209 bytes
  • I've also noticed that each character of the string with all 50 substrings could be encoded in 3 bits, so I stuffed the whole string into one big integer number and then encoded that as a string with base 36. Because the `int()` function can easily decode that back to a number.
  • That's better than the leading solution by Arpad Horvath at the time.
  • ```
  • S="";n=int("1ie3bbwb28v97xgfzvwp5cdss8z4647b6lrucee80ozdnm1e7wjv2fx4vczji4341fpac33oekqbpauv3hxf2hhtk87drmxgdfqis1zua0qe",36)
  • while n:S+=" IVXLCDM"[n&7];n>>=3
  • f=lambda s:next((a for a in S.split()if a in s),1)
  • ```
  • [Try it online!](https://tio.run/##TZA9b4MwEIb3/ArLQwUqqgKmQInIQhekMCEhS1EGA3ZwAsZ8U/48BbLkXe6553Q3nPzr8kogRzbLEnkQnoTHRadAnVOUJGNiOMOPPd3ZPIzyO83a1plNy7QTq2j6lFLnWM2ZKHVqj4/BYJM5pPODm8jUmSQpQhV91okk/YDyiRl53j0dO2vK6Z6xmrf63JNjTaGGLPUw5rygQLjRpwdBEOOL/xvCq/iwbydxPnvowLyClElGQOsKOnWKQgCrGkAAFyD6amXBO0Xl7CVaVdPVZZuLvtzEFQYx1AAM/TU4DnZec/E3Cta8DMbvuK/gcO8x9uHNPQAAZLP9aD2sAbYVVV3@AQ "Python 3.8 (pre-release) – Try It Online")
  • # 235 bytes
  • This is what I was starting with. Pretty straight forward: take the first substring that is contained or 1 if no substring was found.
  • ```
  • f=lambda s:next((a for a in"DD DM IC ID IL IM LC LD LL LM VC VD VL VM VV VX XD XM CCD CCM CDC CMC CMD CMM DCD DCM IIV IIX IVI IXC IXI IXL IXV IXX LXC LXL VIV VIX XCC XCD XCL XCM XCX XLX XXC XXL CCCC IIII MMMM XXXX".split()if a in s),1)
  • ```
  • [Try it online!](https://tio.run/##TY@xasRADET7fMWwlQ0mENKEg1TaRqBthSCkcEhMDHc@Yztw9/XOrNNEMGj0kGbZ@b59X6fnl3nZ9@H13F8@Pnusp@nrtjVNj@G6oMc4pZyRC1SgGWrQAhNYhhmswAWe4Qand3ggMqJAJFPsWSClinMpyOSZXNWpgLpCg@FRO@ODPAJGZpyde869EKEYLUYViswo7gX3hMVAVRQWUUR6XOfzuDXtOBw/wdp2T@1ePzb9XCp4S@qpQyr1OlwPzzKprqb9kYj/9jiJcsx8Pr2fHgDMyzhtDYM7DLW17f4L "Python 3.8 (pre-release) – Try It Online")
  • # Python, 205 bytes
  • Coding the string with the substrings as base 95 number is the shortest I get with this approach:
  • ```python
  • n=0
  • for c in"),|9'OJ#SdHlCSD(LqRhc.|)_#s]`N:?foSIb*.BJVa=AH^).&&w*e(<')vw6T=jv[xbyt8voESZtk>E^5J{,":n=n*94+ord(c)-32
  • S=""
  • while n:S+=" IVXLCDM"[n&7];n>>=3
  • f=lambda s:next((a for a in S.split()if a in s),1)
  • ```
  • [Try it online!](https://tio.run/##TY7dboJAEIXveYrJmuAuUtJqf5R2bVo0EQNt0m3IpkRbBIm0uFCgoKnvTkFv@t3MmTOZk5Pui00iBsM0q2tBz6UwycCHSCCiHkbd53mHBbPYYBNsfb9sfO1A3jv54uNJvw8TZq4U7XHuePRhtiSaLFfKGt91SVldv9LP0t2t9sWwTKbsrfgaT5dX818V6YIKZXTZS7IA@@Rs0JcYRUiqNlG8BqGzHkVgOtwyJjZyhXyzuBXjMR1IIY297SrwINfFeldg7EHb1GuaAtPyNI4KTKLwZOREvSB1exc/29ZwkekgFZBtNHDHPOoGy2iV2XByOP8vjy/cPu6cG2ihSwCQZpEocBOsQtgOQuo/ "Python 3.8 (pre-release) – Try It Online")
  • 206 bytes
  • Arpad Horvath's packing two six bit characters into one ASCII character could make the 209 byte solution even better, so this builds on his work. The unpacking is a bit shorter and the final function works different and is also a bit shorter.
  • ```python
  • n=" IVXLCDM"
  • x="".join(n[(d:=ord(c)-32)>>3]+n[d&7]for c in'&PW!H.!@/$HF$@G"H6"@7"03#P?%N%O%U%]%^%_&N&O!*!+!1!=!9!<!:!;$=$<"*"+#M#N#L#O#K#C#=#<%MH))\'_X;;')
  • f=lambda s:next((a for a in x.split()if a in s),1)
  • ```
  • [Try it online!](https://tio.run/##TY1BT4NAEIXv/IrdWRZ2S0UriVXoVhKMQixtL9ZNKjZYJGLahVBM6q9HaC9@l3nzJvNe9dt8lcq5req2VQJQtJKz4CEG7SgA7O@yUEytWeaKss7Yll8413w6dRJLrTNjnORljbaoUKaxfMWhjf1LPXzU/ScIb8Afw5VDlvd0Thf0hSb0nW6MubHAA2zhERb4Dk@wiz1d6BMYgEViMiczsiDPJCCCTGgccv5mbqTnmVzLxS7df2QpOrjq89gwlqK@PO3K0dE@VLuiYbzIz8aBD0e87e/qZ98ba4hWMEQQBx1yFZ10xyzoVdRxdqT8L08vMj7tUgaQuBpCqKoL1bAueIjyfnDe/gE "Python 3.8 (pre-release) – Try It Online")
  • # 209 bytes
  • I've also noticed that each character of the string with all 50 substrings could be encoded in 3 bits, so I stuffed the whole string into one big integer number and then encoded that as a string with base 36. Because the `int()` function can easily decode that back to a number.
  • That's better than the leading solution by Arpad Horvath at the time.
  • ```python
  • S="";n=int("1ie3bbwb28v97xgfzvwp5cdss8z4647b6lrucee80ozdnm1e7wjv2fx4vczji4341fpac33oekqbpauv3hxf2hhtk87drmxgdfqis1zua0qe",36)
  • while n:S+=" IVXLCDM"[n&7];n>>=3
  • f=lambda s:next((a for a in S.split()if a in s),1)
  • ```
  • [Try it online!](https://tio.run/##TZA9b4MwEIb3/ArLQwUqqgKmQInIQhekMCEhS1EGA3ZwAsZ8U/48BbLkXe6553Q3nPzr8kogRzbLEnkQnoTHRadAnVOUJGNiOMOPPd3ZPIzyO83a1plNy7QTq2j6lFLnWM2ZKHVqj4/BYJM5pPODm8jUmSQpQhV91okk/YDyiRl53j0dO2vK6Z6xmrf63JNjTaGGLPUw5rygQLjRpwdBEOOL/xvCq/iwbydxPnvowLyClElGQOsKOnWKQgCrGkAAFyD6amXBO0Xl7CVaVdPVZZuLvtzEFQYx1AAM/TU4DnZec/E3Cta8DMbvuK/gcO8x9uHNPQAAZLP9aD2sAbYVVV3@AQ "Python 3.8 (pre-release) – Try It Online")
  • # 235 bytes
  • This is what I was starting with. Pretty straight forward: take the first substring that is contained or 1 if no substring was found.
  • ```python
  • f=lambda s:next((a for a in"DD DM IC ID IL IM LC LD LL LM VC VD VL VM VV VX XD XM CCD CCM CDC CMC CMD CMM DCD DCM IIV IIX IVI IXC IXI IXL IXV IXX LXC LXL VIV VIX XCC XCD XCL XCM XCX XLX XXC XXL CCCC IIII MMMM XXXX".split()if a in s),1)
  • ```
  • [Try it online!](https://tio.run/##TY@xasRADET7fMWwlQ0mENKEg1TaRqBthSCkcEhMDHc@Yztw9/XOrNNEMGj0kGbZ@b59X6fnl3nZ9@H13F8@Pnusp@nrtjVNj@G6oMc4pZyRC1SgGWrQAhNYhhmswAWe4Qand3ggMqJAJFPsWSClinMpyOSZXNWpgLpCg@FRO@ODPAJGZpyde869EKEYLUYViswo7gX3hMVAVRQWUUR6XOfzuDXtOBw/wdp2T@1ePzb9XCp4S@qpQyr1OlwPzzKprqb9kYj/9jiJcsx8Pr2fHgDMyzhtDYM7DLW17f4L "Python 3.8 (pre-release) – Try It Online")
#1: Initial revision by user avatar __blackjack__‭ · 2026-03-07T19:29:57Z (6 months ago)
# Python, 206 bytes

Arpad Horvath's packing two six bit characters into one ASCII character could make the 209 byte solution even better, so this builds on his work.  The unpacking is a bit shorter and the final function works different and is also a bit shorter.

```
n=" IVXLCDM"
x="".join(n[(d:=ord(c)-32)>>3]+n[d&7]for c in'&PW!H.!@/$HF$@G"H6"@7"03#P?%N%O%U%]%^%_&N&O!*!+!1!=!9!<!:!;$=$<"*"+#M#N#L#O#K#C#=#<%MH))\'_X;;')
f=lambda s:next((a for a in x.split()if a in s),1)
```
[Try it online!](https://tio.run/##TY1BT4NAEIXv/IrdWRZ2S0UriVXoVhKMQixtL9ZNKjZYJGLahVBM6q9HaC9@l3nzJvNe9dt8lcq5req2VQJQtJKz4CEG7SgA7O@yUEytWeaKss7Yll8413w6dRJLrTNjnORljbaoUKaxfMWhjf1LPXzU/ScIb8Afw5VDlvd0Thf0hSb0nW6MubHAA2zhERb4Dk@wiz1d6BMYgEViMiczsiDPJCCCTGgccv5mbqTnmVzLxS7df2QpOrjq89gwlqK@PO3K0dE@VLuiYbzIz8aBD0e87e/qZ98ba4hWMEQQBx1yFZ10xyzoVdRxdqT8L08vMj7tUgaQuBpCqKoL1bAueIjyfnDe/gE "Python 3.8 (pre-release) – Try It Online")

# 209 bytes

I've also noticed that each character of the string with all 50 substrings could be encoded in 3 bits, so I stuffed the whole string into one big integer number and then encoded that as a string with base 36.  Because the `int()` function can easily decode that back to a number.

That's better than the leading solution by Arpad Horvath at the time.

```
S="";n=int("1ie3bbwb28v97xgfzvwp5cdss8z4647b6lrucee80ozdnm1e7wjv2fx4vczji4341fpac33oekqbpauv3hxf2hhtk87drmxgdfqis1zua0qe",36)
while n:S+=" IVXLCDM"[n&7];n>>=3
f=lambda s:next((a for a in S.split()if a in s),1)
```
[Try it online!](https://tio.run/##TZA9b4MwEIb3/ArLQwUqqgKmQInIQhekMCEhS1EGA3ZwAsZ8U/48BbLkXe6553Q3nPzr8kogRzbLEnkQnoTHRadAnVOUJGNiOMOPPd3ZPIzyO83a1plNy7QTq2j6lFLnWM2ZKHVqj4/BYJM5pPODm8jUmSQpQhV91okk/YDyiRl53j0dO2vK6Z6xmrf63JNjTaGGLPUw5rygQLjRpwdBEOOL/xvCq/iwbydxPnvowLyClElGQOsKOnWKQgCrGkAAFyD6amXBO0Xl7CVaVdPVZZuLvtzEFQYx1AAM/TU4DnZec/E3Cta8DMbvuK/gcO8x9uHNPQAAZLP9aD2sAbYVVV3@AQ "Python 3.8 (pre-release) – Try It Online")

# 235 bytes

This is what I was starting with.  Pretty straight forward: take the first substring that is contained or 1 if no substring was found.

```
f=lambda s:next((a for a in"DD DM IC ID IL IM LC LD LL LM VC VD VL VM VV VX XD XM CCD CCM CDC CMC CMD CMM DCD DCM IIV IIX IVI IXC IXI IXL IXV IXX LXC LXL VIV VIX XCC XCD XCL XCM XCX XLX XXC XXL CCCC IIII MMMM XXXX".split()if a in s),1)
```
[Try it online!](https://tio.run/##TY@xasRADET7fMWwlQ0mENKEg1TaRqBthSCkcEhMDHc@Yztw9/XOrNNEMGj0kGbZ@b59X6fnl3nZ9@H13F8@Pnusp@nrtjVNj@G6oMc4pZyRC1SgGWrQAhNYhhmswAWe4Qand3ggMqJAJFPsWSClinMpyOSZXNWpgLpCg@FRO@ODPAJGZpyde869EKEYLUYViswo7gX3hMVAVRQWUUR6XOfzuDXtOBw/wdp2T@1ePzb9XCp4S@qpQyr1OlwPzzKprqb9kYj/9jiJcsx8Pr2fHgDMyzhtDYM7DLW17f4L "Python 3.8 (pre-release) – Try It Online")