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

如何基于动态格式从歌曲文件名提取元标签?(Bash/Python)

这问题我之前处理过不少,核心思路是把用户提供的元标签格式反向转换成正则表达式——把格式里的%n、%t这类占位符替换成能匹配对应内容的正则分组,再用这个正则去匹配文件名,就能提取出对应的元数据了。下面分别给出Python和Bash的可行实现:

Python 实现

Python的re模块非常适合做这种字符串匹配提取,我们可以写一个通用函数,把格式字符串转成正则,再提取分组内容:

import re

def extract_metadata(filename, format_str):
    # 定义占位符对应的正则规则,可根据需求调整
    placeholder_map = {
        '%n': r'(\d+)',       # 曲目号:匹配数字
        '%t': r'([^.]+?)',    # 标题:匹配到下一个分隔符/后缀前的内容(非贪婪)
        '%a': r'([^.]+?)',    # 艺术家:同理
        '%b': r'([^.]+?)',    # 专辑:同理
    }
    
    # 先转义格式字符串里的正则特殊字符(比如.、-、()等),再替换占位符
    escaped_format = re.escape(format_str)
    for placeholder, regex in placeholder_map.items():
        escaped_format = escaped_format.replace(re.escape(placeholder), regex)
    
    # 匹配文件名(注意要加上$匹配结尾,避免部分匹配)
    match = re.match(f"^{escaped_format}$", filename)
    if not match:
        return None
    
    # 返回提取的元数据字典,键对应占位符去掉%
    metadata = {}
    keys = [p[1:] for p in placeholder_map.keys()]
    for key, value in zip(keys, match.groups()):
        metadata[key] = value.strip()  # 去掉前后空格
    
    return metadata

# 示例调用
filename = "03 - Bohemian Rhapsody - Queen - A Night at the Opera.mp3"
format_str = "%n - %t - %a - %b.mp3"
result = extract_metadata(filename, format_str)
print(result)
# 输出:{'n': '03', 't': 'Bohemian Rhapsody', 'a': 'Queen', 'b': 'A Night at the Opera'}

注意事项

  • 可以根据实际需求调整placeholder_map里的正则规则,比如如果标题允许包含-,可以把%t的正则改成(.+?)(非贪婪匹配到下一个占位符)
  • 如果格式字符串里有自定义分隔符(比如_或者|),只要占位符位置正确,正则会自动适配

Bash 实现

Bash 3.0+支持正则表达式匹配(=~运算符),我们可以用类似的思路,把格式字符串转成正则,再提取匹配结果:

extract_metadata() {
    local filename="$1"
    local format_str="$2"
    
    # 定义占位符对应的正则分组
    declare -A placeholder_map=(
        ['%n']='([0-9]+)'
        ['%t']='([^.]+?)'
        ['%a']='([^.]+?)'
        ['%b']='([^.]+?)'
    )
    
    # 转义格式字符串里的特殊字符,再替换占位符
    local escaped_format=$(printf '%s' "$format_str" | sed 's/[.[\*^$()+?{|]/\\&/g')
    for placeholder in "${!placeholder_map[@]}"; do
        escaped_format=$(printf '%s' "$escaped_format" | sed "s/$(printf '%s' "$placeholder" | sed 's/[\/&]/\\&/g')/${placeholder_map[$placeholder]}/g")
    done
    
    # 执行匹配
    if [[ "$filename" =~ ^$escaped_format$ ]]; then
        # 提取分组,按占位符顺序返回
        local i=1
        for placeholder in '%n' '%t' '%a' '%b'; do
            local key="${placeholder:1}"
            printf "%s=%s\n" "$key" "${BASH_REMATCH[$i]}"
            ((i++))
        done
    else
        echo "No match found" >&2
        return 1
    fi
}

# 示例调用
filename="03 - Bohemian Rhapsody - Queen - A Night at the Opera.mp3"
format_str="%n - %t - %a - %b.mp3"
extract_metadata "$filename" "$format_str"
# 输出:
# n=03
# t=Bohemian Rhapsody
# a=Queen
# b=A Night at the Opera

注意事项

  • Bash的正则匹配默认是贪婪的,所以如果格式里的分隔符和内容可能重叠,需要调整正则规则(比如用[^-]+来匹配到下一个-之前的内容)
  • 转义特殊字符的步骤很重要,否则格式里的.会被当成匹配任意字符,导致错误匹配

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:05:35