Você pode usar o seguinte regex para isso:
^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$
Dividindo, M{0,4}
especifica a seção milhares e basicamente a restringe a entre 0
e 4000
. É relativamente simples:
0: <empty> matched by M{0}
1000: M matched by M{1}
2000: MM matched by M{2}
3000: MMM matched by M{3}
4000: MMMM matched by M{4}
Obviamente, você poderia usar algo como M*
para permitir qualquer número (incluindo zero) de milhares, se desejar permitir números maiores.
A seguir (CM|CD|D?C{0,3})
, um pouco mais complexo, isso é para a seção de centenas e abrange todas as possibilidades:
0: <empty> matched by D?C{0} (with D not there)
100: C matched by D?C{1} (with D not there)
200: CC matched by D?C{2} (with D not there)
300: CCC matched by D?C{3} (with D not there)
400: CD matched by CD
500: D matched by D?C{0} (with D there)
600: DC matched by D?C{1} (with D there)
700: DCC matched by D?C{2} (with D there)
800: DCCC matched by D?C{3} (with D there)
900: CM matched by CM
Em terceiro lugar, (XC|XL|L?X{0,3})
segue as mesmas regras da seção anterior, mas para o lugar das dezenas:
0: <empty> matched by L?X{0} (with L not there)
10: X matched by L?X{1} (with L not there)
20: XX matched by L?X{2} (with L not there)
30: XXX matched by L?X{3} (with L not there)
40: XL matched by XL
50: L matched by L?X{0} (with L there)
60: LX matched by L?X{1} (with L there)
70: LXX matched by L?X{2} (with L there)
80: LXXX matched by L?X{3} (with L there)
90: XC matched by XC
E, finalmente, (IX|IV|V?I{0,3})
é a seção unidades, a manipulação 0
através de 9
e também semelhante às duas seções anteriores (algarismos romanos, apesar de sua estranheza aparente, seguir algumas regras lógicas uma vez que você descobrir o que eles são):
0: <empty> matched by V?I{0} (with V not there)
1: I matched by V?I{1} (with V not there)
2: II matched by V?I{2} (with V not there)
3: III matched by V?I{3} (with V not there)
4: IV matched by IV
5: V matched by V?I{0} (with V there)
6: VI matched by V?I{1} (with V there)
7: VII matched by V?I{2} (with V there)
8: VIII matched by V?I{3} (with V there)
9: IX matched by IX
Lembre-se de que esse regex também corresponderá a uma sequência vazia. Se você não deseja isso (e seu mecanismo de expressão regular é moderno o suficiente), pode usar um look-behind e um look-ahead positivos:
(?<=^)M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})(?=$)
(a outra alternativa é apenas verificar se o comprimento não é zero antes).
MMMM
era o caminho correto. A representação da barra ocorreu muito depois que o império central desmoronou./^M{0,3}(?:C[MD]|D?C{0,3})(?:X[CL]|L?X{0,3})(?:I[XV]|V?I{0,3})$/i
Na verdade, sua premissa é falha. 990 IS "XM", bem como "CMXC".
Os romanos estavam muito menos preocupados com as "regras" do que o seu professor da terceira série. Contanto que tudo funcionasse, tudo bem. Portanto, "IIII" foi tão bom quanto "IV" para 4. E "IIM" foi completamente legal para 998.
(Se você tiver problemas para lidar com isso ... Lembre-se de que as grafias em inglês não foram formalizadas até a década de 1700. Até então, desde que o leitor pudesse descobrir, era bom o suficiente).
fonte
Apenas para salvá-lo aqui:
Corresponde a todos os números romanos. Não se importa com cadeias de caracteres vazias (requer pelo menos uma letra numérica romana). Deve funcionar em PCRE, Perl, Python e Ruby.
Demonstração on-line do Ruby: http://rubular.com/r/KLPR1zq3Hj
Conversão on-line: http://www.onlineconversion.com/roman_numerals_advanced.htm
fonte
Para evitar encontrando a string vazia você precisará repetir o padrão quatro vezes e substituir cada
0
um1
por sua vez, e são responsáveis porV
,L
eD
:Nesse caso (porque esse padrão usa
^
e$
), seria melhor verificar primeiro as linhas vazias e não se incomodar em combiná-las. Se você estiver usando limites de palavras , não terá problemas porque não existe uma palavra vazia. (Pelo menos regex não define um; não comece a filosofar, estou sendo pragmático aqui!)No meu caso particular (do mundo real), eu precisava de números correspondentes às terminações de palavras e não encontrei outra maneira de contornar isso. Eu precisava retirar os números das notas de rodapé do meu documento de texto sem formatação, onde textos como "o cl do Mar Vermelho e o cli da Grande Barreira de Corais " haviam sido convertidos
the Red Seacl and the Great Barrier Reefcli
. Mas eu ainda tinha problemas com palavras válidas comoTahiti
efantastic
são arrastados paraTahit
efantasti
.fonte
M
ouC
ouL
, então, você tem isso tipo de regex simplificado?(X{1,3}(IX|IV|V?I{0,3})|X{0,3}(IX|I?V|V?I{1,3}))
Felizmente, o intervalo de números é limitado a 1..3999 ou aproximadamente. Portanto, você pode criar a refeição regular regex.
Cada uma dessas partes lidará com os caprichos da notação romana. Por exemplo, usando a notação Perl:
Repita e monte.
Adicionado : O
<opt-hundreds-part>
pode ser comprimido ainda mais:Como a cláusula 'D? C {0,3}' pode corresponder a nada, não há necessidade do ponto de interrogação. E, provavelmente, os parênteses devem ser do tipo não capturável - em Perl:
Obviamente, tudo também não diferencia maiúsculas de minúsculas.
Você também pode estender isso para lidar com as opções mencionadas por James Curran (para permitir XM ou IM para 990 ou 999, e CC0 para 400, etc.).
fonte
thousands hundreds tens units
, é fácil criar um FSM que calcule e valide dados de números romanosPara pessoas que realmente querem entender a lógica, dê uma olhada em uma explicação passo a passo em 3 páginas no diveintopython .
A única diferença em relação à solução original (que tinha
M{0,4}
) é porque descobri que 'MMMM' não é um número romano válido (também os romanos antigos provavelmente não pensaram nesse número enorme e discordarão de mim). Se você é um dos antigos romanos em desacordo, por favor me perdoe e use a versão {0,4}.fonte
Estou respondendo a esta pergunta Expressão regular em Python para algarismos romanos aqui,
porque foi marcada como uma duplicata exata desta pergunta.
Pode ser semelhante no nome, mas esta é uma pergunta / problema específico do regex
como pode ser visto por esta resposta a essa pergunta.
Os itens procurados podem ser combinados em uma única alternância e, em seguida,
envoltos em um grupo de captura que será colocado em uma lista com a
função findall () .
É feito assim:
As modificações de regex para fatorar e capturar apenas os números são as seguintes:
fonte
Como Jeremy e Pax apontaram acima ... '^ M {0,4} (CM | CD | D? C {0,3}) (XC | XL | L? X {0,3}) (IX | IV | V? I {0,3}) $ 'deve ser a solução que você procura ...
O URL específico que deveria ter sido anexado (IMHO) é http://thehazeltree.org/diveintopython/7.html
O exemplo 7.8 é o formato abreviado usando {n, m}
fonte
No meu caso, eu estava tentando encontrar e substituir todas as ocorrências de números romanos por uma palavra dentro do texto, para não poder usar o início e o fim das linhas. Portanto, a solução @paxdiablo encontrou muitas correspondências de comprimento zero. Acabei com a seguinte expressão:
Meu código Python final era assim:
Resultado:
fonte
Steven Levithan usa esse regex em seu post, que valida números romanos antes de "desmanchar" o valor:
fonte
Eu já vi várias respostas que não cobrem cadeias vazias ou usam viseiras para resolver isso. E quero adicionar uma nova resposta que cubra cadeias vazias e não use lookahead. A regex é a seguinte:
^(I[VX]|VI{0,3}|I{1,3})|((X[LC]|LX{0,3}|X{1,3})(I[VX]|V?I{0,3}))|((C[DM]|DC{0,3}|C{1,3})(X[LC]|L?X{0,3})(I[VX]|V?I{0,3}))|(M+(C[DM]|D?C{0,3})(X[LC]|L?X{0,3})(I[VX]|V?I{0,3}))$
Estou permitindo infinito
M
,M+
mas é claro que alguém poderia mudarM{1,4}
para permitir apenas 1 ou 4, se desejado.Abaixo está uma visualização que ajuda a entender o que está fazendo, precedida por duas demos online:
Demo de depuração
Regex 101 Demo
fonte
Isso funciona nos mecanismos regex Java e PCRE e agora deve funcionar no JavaScript mais recente, mas pode não funcionar em todos os contextos.
(?<![A-Z])(M*(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3}))(?![A-Z])
A primeira parte é o olhar negativo atroz. Mas, para fins lógicos, é o mais fácil de entender. Basicamente, o primeiro
(?<!)
está dizendo não corresponder ao meio,([MATCH])
se houver letras chegando antes do meio,([MATCH])
e o último(?!)
está dizendo não corresponder ao meio,([MATCH])
se houver letras após ele.O meio
([MATCH])
é apenas o regex mais comumente usado para corresponder à sequência de algarismos romanos. Mas agora, você não quer combinar isso se houver alguma letra em torno dele.Veja por si mesmo. https://regexr.com/4vce5
fonte
O problema da solução de Jeremy e Pax é que ele também não corresponde a "nada".
O seguinte regex espera pelo menos um número romano:
fonte
|
pode corresponder a uma sequência vazia e a todos os algarismos romanos válidos; portanto, o lado direito é completamente redundante. e sim, ainda corresponde a uma sequência vazia.Eu escreveria funções para o meu trabalho para mim. Aqui estão duas funções de números romanos no PowerShell.
fonte