<p>使用<code>re.sub</code>:</p>
<pre><code>re.sub(r'(?i)^(.*?)\s*(PNo)\s*(\d{4})\s*(?:-\s*)?(.*)$', r'\2 \3 - \1 \4', string)
</code></pre>
<p>见<a href="https://regex101.com/r/BIikWF/1" rel="nofollow noreferrer">proof</a></p>
<p>说明:</p>
<pre><code>NODE EXPLANATION
(?i) set flags for this block (case-
insensitive) (with ^ and $ matching
normally) (with . not matching \n)
(matching whitespace and # normally)
^ the beginning of the string
( group and capture to \1:
.*? any character except \n (0 or more times
(matching the least amount possible))
) end of \1
\s* whitespace (\n, \r, \t, \f, and " ") (0 or
more times (matching the most amount
possible))
( group and capture to \2:
PNo 'PNo'
) end of \2
\s* whitespace (\n, \r, \t, \f, and " ") (0 or
more times (matching the most amount
possible))
( group and capture to \3:
\d{4} digits (0-9) (4 times)
) end of \3
\s* whitespace (\n, \r, \t, \f, and " ") (0 or
more times (matching the most amount
possible))
(?: group, but do not capture (optional
(matching the most amount possible)):
- '-'
\s* whitespace (\n, \r, \t, \f, and " ") (0
or more times (matching the most amount
possible))
)? end of grouping
( group and capture to \4:
.* any character except \n (0 or more times
(matching the most amount possible))
) end of \4
$ before an optional \n, and the end of the
string
</code></pre>