<p><code>^ab|cd$</code>表示</p>
<ol>
<li>字符串的开头,后跟<code>ab</code><strong>或</strong></li>
<li><code>cd</code>后跟字符串结尾。在</li>
</ol>
<p>也就是说,<strong><code>ab</code></strong><code>123</code>匹配,因为粗体部分匹配<strong>1</strong>,并且
<code>123</code><strong><code>cd</code></strong>匹配,因为粗体部分匹配<strong>2</strong>。也就是说,<code>|</code>符号的优先级在所有符号中最低。在</p>
<p>与<code>.search</code>一起使用时,它与<code>s.startswith('ab') or s.endswith('cd')</code>相同;但是
如果使用<code>.match</code>而不是<code>.search</code>,则模式必须在字符串的开头匹配<em>,因此得到<code>s.startswith('ab') or s == 'cd'</code>。在</p>
<p><code>^(ab|cd)$</code>表示</p>
<ul>
<li>字符串的开头,后跟<code>ab</code>或{<cd3>},然后接字符串结尾</li>
<li>与<code>ab|cd</code>匹配的任何内容都可以作为<code>match.group(1)</code>获得</li>
</ul>
<p><code>^(ab)|(cd)$</code>与第一个相同,只是如果<code>ab</code>匹配,它可用作<code>match.group(1)</code>,同样地,<code>cd</code>如果匹配,匹配该部分的文本可用作<code>match.group(2)</code>。在</p>
<p>注意,<code>(...)</code>在正则表达式中有两个用途-它们将原子分组到一个原子中,并使匹配的文本在match对象中可用。如果您只需要分组,您应该使用<code>(?:...)</code>,因为生成子匹配字符串的成本很高。在</p>
<hr/>
<p>至于您的罗马数字正则表达式的问题,您在上层错误地使用了<code>|</code>分支。在</p>
<pre><code>^M{1,3}|(CM|C?D|D?C{1,3})|(X?L|XC|L?X{1,3})|(I?V|IX|V?I{1,3})$
</code></pre>
<p>如果与<code>.match</code>(与<code>.search</code>一起使用,2-4甚至没有绑定到字符串的开头),它代表</p>
<ol>
<li>字符串的开头后跟<code>M{1,3}</code>以及其后的任何内容<em>或</em></li>
<li>字符串的开头后跟<code>CM|C?D|D?C{1,3}</code>以及其后的任何内容<em>或</em></li>
<li>字符串的开头后跟<code>X?L|XC|L?X{1,3}</code>以及其后的任何内容<em>或</em></li>
<li>字符串的开头后跟<code>I?V|IX|V?I{1,3}</code>,然后是字符串的结尾。在</li>
</ol>
<hr/>
<p>您不希望在主级别使用<code>|</code>,而是将这1-4中的每一个都作为可选的,使用<code>?</code>;而且您通常希望使用非捕获组(<code>(?: )</code>)进行分组。因此我们得到:</p>
^{pr2}$
<p>但它仍然匹配空字符串。要使其不匹配空字符串,可以使用<em>零宽度正前向查找</em>来要求整个构造至少匹配1个(任意)字符。在</p>
<p>从<a href="https://docs.python.org/3/library/re.html" rel="nofollow">Python docs</a></p>
<blockquote>
<p><code>(?=...)</code>
Matches if <code>...</code> matches next, but doesn’t consume any of the string. This is called a lookahead assertion. For example, <code>Isaac (?=Asimov)</code> will match <code>'Isaac '</code> only if it’s followed by <code>'Asimov'</code>.</p>
</blockquote>
<p>因此,我们可以将它放在字符串锚定符<code>^</code>的开头之后,以确保整个字符串至少匹配<code>^.</code>(即,字符串的开头后跟1个字符):</p>
<pre><code>^(?=.)(?:M{1,3})?(?:CM|C?D|D?C{1,3})?(?:X?L|XC|L?X{1,3})?(?:I?V|IX|V?I{1,3})?$
</code></pre>
<p>也就是说:</p>
<ul>
<li>字符串开头(<code>^</code>)</li>
<li>字符串结束前至少有1个字符(<code>(?=.)</code>)</li>
<li><code>M{1,3}</code>(可选),后跟</li>
<li><code>CM|C?D|D?C{1,3}</code>(可选),后跟</li>
<li><code>X?L|XC|L?X{1,3}</code>(可选),后跟</li>
<li><code>I?V|IX|V?I{1,3}</code>(可选),后跟</li>
<li>字符串结尾<code>$</code></li>
</ul>
<p>这应该是你想要的。在</p>