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

如何优化正则表达式实现西班牙语大数文本的数字替换?

西班牙语大数表述转数字串:正则优化与替代实现方案

核心需求回顾

仅对连续的大数表述序列(如"tres millones dos mil")执行转换,孤立的大数单位(如单独的"mil"或"un millón")不处理;需兼容单位单复数规则及语法例外(如mil单复数同形,un millón单数搭配、dos millones复数搭配),单位数值映射如下:

  • mil → 1000
  • millon/millones → 1,000,000
  • billon/billones → 1,000,000,000
  • trillon/trillones → 1,000,000,000,000
  • cuatrillon/cuatrillon → 1,000,000,000,000,000

正则表达式优化方案

问题分析

原型正则通常存在以下缺陷:未匹配连续序列结构、未处理单复数变体、未兼容西班牙语数词/阿拉伯数字混合场景、未通过断言限制孤立单位。

优化后的正则(支持阿拉伯数字+西班牙语基数词)

\b(?:(?:\d+|un|una|dos|tres|cuatro|cinco|seis|siete|ocho|nueve|diez|once|doce|trece|catorce|quince|dieciséis|diecisiete|dieciocho|diecinueve|veinte|veintiún|veintidós|veintitrés|veinticuatro|veinticinco|veintiséis|veintisiete|veintiocho|veintinueve|treinta|cuarenta|cincuenta|sesenta|setenta|ochenta|noventa|cien|ciento|doscientos|trescientos|cuatrocientos|quinientos|seiscientos|setecientos|ochocientos|novecientos)\s+(?:mil|mill(?:ón|ones)|bill(?:ón|ones)|trill(?:ón|ones)|cuatrill(?:ón|ones)))(?:\s+(?:\d+|un|una|dos|tres|cuatro|cinco|seis|siete|ocho|nueve|diez|once|doce|trece|catorce|quince|dieciséis|diecisiete|dieciocho|diecinueve|veinte|veintiún|veintidós|veintitrés|veinticuatro|veinticinco|veintiséis|veintisiete|veintiocho|veintinueve|treinta|cuarenta|cincuenta|sesenta|setenta|ochenta|noventa|cien|ciento|doscientos|trescientos|cuatrocientos|quinientos|seiscientos|setecientos|ochocientos|novecientos)\s+(?:mil|mill(?:ón|ones)|bill(?:ón|ones)|trill(?:ón|ones)|cuatrill(?:ón|ones)))+\b

关键优化点

  1. 连续序列匹配:通过(?:...)+\b确保匹配由多个「数词+单位」组成的连续序列,避免匹配孤立单位。
  2. 单复数兼容:用mill(?:ón|ones)匹配millon/millones,同理处理其他单位的单复数变体。
  3. 数词覆盖:包含常用西班牙语基数词和阿拉伯数字,适配混合场景。
  4. 边界限制:用\b单词边界确保序列前后无其他数词/单位,避免部分匹配。

配合替换函数使用

正则仅负责匹配序列,需通过替换函数完成数值计算:

  1. 捕获序列内的每个「数词+单位」对。
  2. 将西班牙语数词转为阿拉伯数字(需提前定义映射表)。
  3. 按单位数值计算每个部分的数值,求和后转为字符串替换原序列。

更可靠的替代实现:分词+语法分析

当场景涉及复杂数词(如复合数词"ciento veinte")或特殊语法例外时,正则的可维护性会下降,建议采用以下流程:

  1. 分词:将输入字符串按空格拆分为词列表。
  2. 序列检测:滑动遍历词列表,标记连续的「数词+单位」对组成的序列(需排除孤立单位)。
  3. 数值计算:
    • 用预定义的数词→数字映射表转换数词。
    • 用单位→数值映射表计算每个部分的贡献,求和得到总数值。
  4. 替换回原字符串:将标记的序列替换为总数值的字符串。

代码示例(Python)

# 数词转数字映射表
NUM_MAP = {
    "un": 1, "una": 1, "dos": 2, "tres": 3, "cuatro": 4, "cinco": 5,
    "seis": 6, "siete": 7, "ocho": 8, "nueve": 9, "diez": 10,
    "cien": 100, "doscientos": 200, "trescientos": 300,
    # 可扩展更多数词...
}

# 单位转数值映射表
UNIT_MAP = {
    "mil": 1000,
    "millon": 1_000_000, "millones": 1_000_000,
    "billon": 1_000_000_000, "billones": 1_000_000_000,
    "trillon": 1_000_000_000_000, "trillones": 1_000_000_000_000,
    "cuatrillon": 1_000_000_000_000_000, "cuatrillones": 1_000_000_000_000_000
}

def convert_large_numbers(text):
    words = text.split()
    result = []
    i = 0
    n = len(words)
    
    while i < n:
        # 检测是否进入连续大数序列
        if i + 1 < n and words[i] in NUM_MAP and words[i+1] in UNIT_MAP:
            sequence_total = 0
            # 遍历整个连续序列
            while i + 1 < n and words[i] in NUM_MAP and words[i+1] in UNIT_MAP:
                num = NUM_MAP[words[i]]
                unit_val = UNIT_MAP[words[i+1]]
                sequence_total += num * unit_val
                i += 2
            result.append(str(sequence_total))
        else:
            # 非序列内容直接保留
            result.append(words[i])
            i += 1
    
    return " ".join(result)

# 测试示例
input_text = "tres millones dos mil cincuenta pesos"
print(convert_large_numbers(input_text))
# 输出:"3002000 cincuenta pesos"

内容的提问来源于stack exchange,提问作者Santiago Nahuel Rodriguez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 07:15:33