You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从SourceForge不同命名规范的软件包中提取版本号

SourceForge 软件版本号提取方案

直接用多规则加权打分+干扰项过滤的思路实现,仅依赖Python标准库即可覆盖绝大多数项目的命名场景,识别准确率远高于单纯正则匹配。

核心逻辑

  • 路径拆分预处理:将输入的文件路径按/切分为独立的目录段、文件名段逐段匹配,避免整串正则匹配引入无关干扰
  • 干扰项前置过滤:提前排除架构、系统、语言、日期类无效数字串,包括x86/x64/amd64/arm64等硬件架构标识、win/linux/macos等系统标识、en-US/zh-CN等语言标识、8位纯数字组成的发布日期串,以及zip/exe/iso等后缀名相关字段
  • 候选版本匹配:用宽松正则抓取所有符合版本号特征的候选串,规则为匹配至少包含2段数字分隔的字符串(如22.00/2.51.1/3.3.0均符合,单段数字如86/64直接排除),同时兼容v1.2.3/ver2.4/3.0.0-beta这类带前缀、预发布标识的版本格式
  • 可信度加权排序:对所有候选按规则打分,得分最高的即为最终版本号,打分规则如下:
    • 候选出现在目录段:+30分(SourceForge多数项目会将版本号设为独立目录,可信度最高)
    • 候选在同一路径中重复出现:每多出现1次+20分
    • 候选与项目名称在同一段中相邻(如KeePass-2.51.1.zip中版本号紧跟项目名):+15分
    • 候选前带v/ver/version等版本标识前缀:+10分
    • 候选嵌在无分隔的长字符串中(如7z2200中的数字段):-20分

可直接运行的实现代码

import re
from collections import defaultdict

# 非版本号排除关键词,可根据实际遇到的场景持续补充
EXCLUDE_WORDS = {
    'x86', 'x64', 'amd64', 'arm64', 'armv7', 'armv8', 'i386', 'i686',
    'win', 'win32', 'win64', 'linux', 'darwin', 'mac', 'macos', 'osx',
    'en', 'zh', 'cn', 'us', 'de', 'fr', 'jp', 'ko', 'install', 'setup',
    'tar', 'xz', 'zip', 'gz', 'bz2', 'exe', 'msi', 'iso', 'src', 'bin'
}
# 版本号匹配正则
VERSION_PATTERN = re.compile(
    r'(?:v|V|ver|Ver|version|Version)?[._-]?(\d+(?:[._-]\d+){1,4})(?:[._-]?(?:alpha|beta|rc|RC|dev|stable|final))?'
)
# 8位纯日期格式正则(如20110219)
DATE_PATTERN = re.compile(r'^\d{8}$')

def extract_version(file_path: str, proj_name: str = "") -> str:
    candidate_scores = defaultdict(int)
    path_segments = [seg for seg in file_path.split('/') if seg]
    total_seg = len(path_segments)

    for seg_idx, segment in enumerate(path_segments):
        matches = VERSION_PATTERN.finditer(segment)
        for match in matches:
            ver_candidate = match.group(1)
            # 过滤无效候选
            clean_ver = ver_candidate.lower().replace('.', '').replace('-', '').replace('_', '')
            if ver_candidate.lower() in EXCLUDE_WORDS:
                continue
            if DATE_PATTERN.match(clean_ver):
                continue
            # 按规则打分
            # 目录段加权
            if seg_idx != total_seg - 1:
                candidate_scores[ver_candidate] += 30
            # 出现次数加权
            candidate_scores[ver_candidate] += 20
            # 紧邻项目名加权
            if proj_name and proj_name.lower().split('.')[0] in segment.lower():
                proj_pos = segment.lower().find(proj_name.lower().split('.')[0])
                if abs(match.start() - proj_pos) < len(proj_name) + 3:
                    candidate_scores[ver_candidate] += 15
            # 带版本前缀加权
            prefix = match.group(0).lower()
            if prefix.startswith(('v', 'ver', 'version')):
                candidate_scores[ver_candidate] += 10
            # 嵌在无分隔长串中减分
            if match.start() > 0:
                prev_char = segment[match.start()-1]
                if not (prev_char in '._-' or prev_char.isalpha() and prev_char.lower() in 'ver'):
                    candidate_scores[ver_candidate] -= 20
    
    if not candidate_scores:
        return ""
    # 取得分最高的候选,统一分隔符为点
    best_ver = max(candidate_scores.items(), key=lambda x: x[1])[0]
    return best_ver.replace('_', '.').replace('-', '.')

# 测试验证
if __name__ == "__main__":
    test_cases = [
        ("/7-Zip/22.00/7z2200-linux-x86.tar.xz", "sevenzip"),
        ("/KeePass 2.x/2.51.1/KeePass-2.51.1.zip", "keepass"),
        ("/extended/iso/en/OOo_3.3.0_Win_x86_install_en-US_20110219.iso", "openofficeorg.mirror")
    ]
    for path, proj in test_cases:
        print(f"{proj} 提取版本: {extract_version(path, proj)}")

测试结果

  • 7-Zip 提取结果:22.00
  • KeePass 提取结果:2.51.1
  • OpenOffice.org 提取结果:3.3.0

后续如果遇到识别偏差的项目,只需要把对应特有的干扰关键词补充到EXCLUDE_WORDS列表中即可,不需要修改核心逻辑,覆盖的项目越多识别准确率越高。


内容的提问来源于stack exchange,提问作者Alureon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 15:57:14