Python替换多格式代码版本号的最优方案(兼容单双引号)
Let's get your version update function working reliably for both files, while supporting both single and double quotes. Here's the step-by-step solution:
The Root Cause
Your original regex likely had two key gaps:
- It only targeted lines starting with
__version__, ignoring theversion = ...pattern in setup.py - It didn't account for both single (
') and double (") quotes, or failed to preserve the original quote type when replacing
Optimal Implementation
Here's a robust update_version_strings function that fixes both issues and handles edge cases like inconsistent whitespace:
import re def update_version_strings(file_path: str, new_version: str) -> None: # Regex pattern that matches both version variable types, any quote style, and flexible whitespace # Breakdown of the pattern: # ^ : Anchor to the start of a line # (\s*(?:__version__|version)\s*=\s*) : Capture group 1: variable name, equals sign, and surrounding whitespace # (['"]) : Capture group 2: the opening quote (single or double, preserves original style) # (.*?) : Capture group 3: the old version string (non-greedy match to avoid overshooting) # \2 : Match the closing quote (matches whatever was captured in group 2) # $ : Anchor to the end of a line version_pattern = re.compile(r'^(\s*(?:__version__|version)\s*=\s*)([\'"])(.*?)\2$', re.MULTILINE) # Read and modify the file safely with context managers with open(file_path, 'r', encoding='utf-8') as f: content = f.read() # Replace using captured groups to keep original formatting intact updated_content = version_pattern.sub(rf'\1\2{new_version}\2', content) with open(file_path, 'w', encoding='utf-8') as f: f.write(updated_content)
Key Features Explained
- Dual File Support: The regex matches both
__version__(for__init__.py) andversion(forsetup.py) lines in one go - Quote Preservation: Captures the original quote type and reuses it in the replacement, so you don't mess with the file's existing style
- Whitespace Tolerance: Handles any amount of space around the equals sign (e.g.,
version = "0.1.3"or__version__="0.1.3") - Line-Specific Matching: The
re.MULTILINEflag ensures we only modify lines that explicitly declare the version variable
Testing It Out
Let's verify with sample content for both files:
For foopkg/__init__.py
Original:
__version__ = "0.1.3" # Or with single quotes: # __version__ = '0.1.3'
After calling update_version_strings("foopkg/__init__.py", "0.2.0"):
__version__ = "0.2.0" # Or if original had single quotes: # __version__ = '0.2.0'
For setup.py
Original:
from setuptools import setup setup( name="foopkg", version = '0.1.3', # Or with double quotes: # version = "0.1.3", ... )
After calling update_version_strings("setup.py", "0.2.0"):
from setuptools import setup setup( name="foopkg", version = '0.2.0', # Or if original had double quotes: # version = "0.2.0", ... )
Why This Works Better Than Your Original Code
By using a single, flexible regex that targets both variable names and preserves formatting, you avoid needing separate logic for each file. The capture groups ensure only the version number changes—everything else (whitespace, quote style) stays exactly as it was.
内容的提问来源于stack exchange,提问作者Justin Mayer

