[Python] Find roman numerals case-insensitively in regular text

Discussão em 'Python' iniciado por Stack, Agosto 1, 2025.

  1. Stack

    Stack Membro Participativo

    The regexes found in the answers to this SO question have various problems with finding only valid roman numbers that are within regular text (not on a line by themselves). (To be clear, that wasn't a requirement of the original question, but a couple of the answers did try to address it).

    The core issue is that, although various methods are used to not match an empty string, none of them handle an empty match. That is, it's possible for a match itself to be empty, even if the string isn't.

    I've searched quite a bit for other possible solutions, and they're either marked as duplicate and closed due to the one above (SO), or the answers aren't any better (SO and external).

    Small amount of test data to demonstrate the problem:

    <p>Charles I was a bad king, I was not.</p>
    <p>Charles X was a good one.</p>
    <p>Who was Louis XVI?</p>
    <p>The year is MCMXCIX, the month is June.</p>
    <p>Do you need an X-ray, do you think?</p>
    <p>My friends Cil and Cleo met me for coffee.</p>
    <p>MCMLXIX</p>


    This is the best regex I could identify of the group for this particular problem, improved slightly (it doesn't work without the changes, either, so I don't believe they're the problem).

    (?=\b[MCDXLVI]+\b)M{0,4}(?:CM|CD|D?C{0,3})(?:XC|XL|L?X{0,3})(?:IX|IV|V?I{0,3})(?!-)\b

    This regex (in case-insensitive mode) finds all of the valid roman numbers in the above test data (including the false-positive "I" in "I was not", but that is to be expected and not an issue), but has two empty matches: the empty string prior to the X in X-ray in the 5th line, and the empty string prior to Cil in the next-to-last-line.

    This occurs because both "X" and "Cil" pass the lookahead since they contain solely roman numeral characters, but the rest of the regex doesn't match anything due to the trailing dash in the first case and Cil not being a valid roman number in the second case. Thus in each case there's a match, but it's empty.

    The question: is it possible to modify the regex to not allow an empty match? (No empty match at all, not just on this test data.)

    Ultimately this will be in python 3, but I've also been testing in a PCRE2 editor for convenience. (And in regex101 with both PCRE2 and python for a sanity check.) For completeness, although it's in python, the solution needs to be a single regex, not programmatic, e.g. looping through matches.

    Continue reading...

Compartilhe esta Página