擅长:python、mysql、java
<p>如果要使用<code>findall</code>或<code>finditer</code>方法在字符串中查找多个罗马数字,一种可能的模式是:</p>
<pre><code>(?=[MDCXLVI])(?<![MDCXLVI])M{0,4}(?:C[MD]|D?C{0,3})(?:X[CL]|L?X{0,3})(?:I[XV]|V?I{0,3})(?![MDCXLVI])
</code></pre>
<p>它有点长,我会解释为什么我认为它是有效的:</p>
<p><code>(?=[MDCXLVI])</code>是一个lookahead,它检查位置后面是否跟有这些字符之一。此前瞻有两个功能:</p>
<ul>
<li><p>第一种是模拟一种<em>第一字符识别</em>,以快速避免所有不包含这些字符的位置(这样,regex引擎就不需要用<code>M{0,4}(?:C[MD]|D?C{0,3})(?:X[CL]|L?X{0,3})(?:I[XV]|V?I{0,3})</code>测试所有可能的开头)。</p></li>
<li><p>第二个检查是否至少有一个字符,因为<code>M{0,4}(?:C[MD]|D?C{0,3})(?:X[CL]|L?X{0,3})(?:I[XV]|V?I{0,3})</code>可以匹配空字符串。</p></li>
</ul>
<p><code>(?<![MDCXVLI])</code>和<code>(?![MDCXVLI])</code>被用作边界,以确保周围没有其他“罗马字符”(否则像<code>ILVIII</code>这样的子字符串将返回<code>LVIII</code>,而不是跳过格式错误的整个字符组)。<em>注意,其他类型的边界也是可能的,比如<code>\b</code>或<code>(?<![^\s,])</code><code>(?![^\s,])</code>。。。取决于字符串格式。</em>还要注意,左边界只放在<code>(?=[MDCXVLI])</code>之后,这样就不会破坏第一个字符的区分。你知道吗</p>
<p>像<code>CM|CD</code>这样的交替被减少到<code>C[MD]</code>。你知道吗</p>
<p>该模式仅使用非捕获组<code>(?:...)</code>来保留内存并避免未使用的存储任务。你知道吗</p>