CoolFace
Apppublic

ASLP-lab/DiffRhythm

sourceHugging Faceapache-2.0updated 1y agoView on Hugging Face
689likes
num.py327 linesDownload Raw Back to utils
1# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7#     http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14# Digital processing from GPT_SoVITS num.py (thanks)15"""16Rules to verbalize numbers into Chinese characters.17https://zh.wikipedia.org/wiki/中文数字#現代中文18"""19 20import re21from collections import OrderedDict22from typing import List23 24DIGITS = {str(i): tran for i, tran in enumerate('零一二三四五六七八九')}25UNITS = OrderedDict({26    1: '十',27    2: '百',28    3: '千',29    4: '万',30    8: '亿',31})32 33COM_QUANTIFIERS = '(处|台|架|枚|趟|幅|平|方|堵|间|床|株|批|项|例|列|篇|栋|注|亩|封|艘|把|目|套|段|人|所|朵|匹|张|座|回|场|尾|条|个|首|阙|阵|网|炮|顶|丘|棵|只|支|袭|辆|挑|担|颗|壳|窠|曲|墙|群|腔|砣|座|客|贯|扎|捆|刀|令|打|手|罗|坡|山|岭|江|溪|钟|队|单|双|对|出|口|头|脚|板|跳|枝|件|贴|针|线|管|名|位|身|堂|课|本|页|家|户|层|丝|毫|厘|分|钱|两|斤|担|铢|石|钧|锱|忽|(千|毫|微)克|毫|厘|(公)分|分|寸|尺|丈|里|寻|常|铺|程|(千|分|厘|毫|微)米|米|撮|勺|合|升|斗|石|盘|碗|碟|叠|桶|笼|盆|盒|杯|钟|斛|锅|簋|篮|盘|桶|罐|瓶|壶|卮|盏|箩|箱|煲|啖|袋|钵|年|月|日|季|刻|时|周|天|秒|分|小时|旬|纪|岁|世|更|夜|春|夏|秋|冬|代|伏|辈|丸|泡|粒|颗|幢|堆|条|根|支|道|面|片|张|颗|块|元|(亿|千万|百万|万|千|百)|(亿|千万|百万|万|千|百|美|)元|(亿|千万|百万|万|千|百|十|)吨|(亿|千万|百万|万|千|百|)块|角|毛|分)'34 35# 分数表达式36RE_FRAC = re.compile(r'(-?)(\d+)/(\d+)')37 38 39def replace_frac(match) -> str:40    """41    Args:42        match (re.Match)43    Returns:44        str45    """46    sign = match.group(1)47    nominator = match.group(2)48    denominator = match.group(3)49    sign: str = "负" if sign else ""50    nominator: str = num2str(nominator)51    denominator: str = num2str(denominator)52    result = f"{sign}{denominator}分之{nominator}"53    return result54 55 56# 百分数表达式57RE_PERCENTAGE = re.compile(r'(-?)(\d+(\.\d+)?)%')58 59 60def replace_percentage(match) -> str:61    """62    Args:63        match (re.Match)64    Returns:65        str66    """67    sign = match.group(1)68    percent = match.group(2)69    sign: str = "负" if sign else ""70    percent: str = num2str(percent)71    result = f"{sign}百分之{percent}"72    return result73 74 75# 整数表达式76# 带负号的整数 -1077RE_INTEGER = re.compile(r'(-)' r'(\d+)')78 79 80def replace_negative_num(match) -> str:81    """82    Args:83        match (re.Match)84    Returns:85        str86    """87    sign = match.group(1)88    number = match.group(2)89    sign: str = "负" if sign else ""90    number: str = num2str(number)91    result = f"{sign}{number}"92    return result93 94 95# 编号-无符号整形96# 0007897RE_DEFAULT_NUM = re.compile(r'\d{3}\d*')98 99 100def replace_default_num(match):101    """102    Args:103        match (re.Match)104    Returns:105        str106    """107    number = match.group(0)108    return verbalize_digit(number, alt_one=True)109 110 111# 加减乘除112# RE_ASMD = re.compile(113#     r'((-?)((\d+)(\.\d+)?)|(\.(\d+)))([\+\-\×÷=])((-?)((\d+)(\.\d+)?)|(\.(\d+)))')114RE_ASMD = re.compile(115    r'((-?)((\d+)(\.\d+)?[⁰¹²³⁴⁵⁶⁷⁸⁹ˣʸⁿ]*)|(\.\d+[⁰¹²³⁴⁵⁶⁷⁸⁹ˣʸⁿ]*)|([A-Za-z][⁰¹²³⁴⁵⁶⁷⁸⁹ˣʸⁿ]*))([\+\-\×÷=])((-?)((\d+)(\.\d+)?[⁰¹²³⁴⁵⁶⁷⁸⁹ˣʸⁿ]*)|(\.\d+[⁰¹²³⁴⁵⁶⁷⁸⁹ˣʸⁿ]*)|([A-Za-z][⁰¹²³⁴⁵⁶⁷⁸⁹ˣʸⁿ]*))')116 117asmd_map = {118    '+': '加',119    '-': '减',120    '×': '乘',121    '÷': '除',122    '=': '等于'123}124 125def replace_asmd(match) -> str:126    """127    Args:128        match (re.Match)129    Returns:130        str131    """132    result = match.group(1) + asmd_map[match.group(8)] + match.group(9)133    return result134 135 136# 次方专项137RE_POWER = re.compile(r'[⁰¹²³⁴⁵⁶⁷⁸⁹ˣʸⁿ]+')138 139power_map = {140    '⁰': '0',141    '¹': '1',142    '²': '2',143    '³': '3',144    '⁴': '4',145    '⁵': '5',146    '⁶': '6',147    '⁷': '7',148    '⁸': '8',149    '⁹': '9',150    'ˣ': 'x',151    'ʸ': 'y',152    'ⁿ': 'n'153}154 155def replace_power(match) -> str:156    """157    Args:158        match (re.Match)159    Returns:160        str161    """162    power_num = ""163    for m in match.group(0):164        power_num += power_map[m]165    result = "的" + power_num + "次方"166    return result167 168 169# 数字表达式170# 纯小数171RE_DECIMAL_NUM = re.compile(r'(-?)((\d+)(\.\d+))' r'|(\.(\d+))')172# 正整数 + 量词173RE_POSITIVE_QUANTIFIERS = re.compile(r"(\d+)([多余几\+])?" + COM_QUANTIFIERS)174RE_NUMBER = re.compile(r'(-?)((\d+)(\.\d+)?)' r'|(\.(\d+))')175 176 177def replace_positive_quantifier(match) -> str:178    """179    Args:180        match (re.Match)181    Returns:182        str183    """184    number = match.group(1)185    match_2 = match.group(2)186    if match_2 == "+":187        match_2 = "多"188    match_2: str = match_2 if match_2 else ""189    quantifiers: str = match.group(3)190    number: str = num2str(number)191    result = f"{number}{match_2}{quantifiers}"192    return result193 194 195def replace_number(match) -> str:196    """197    Args:198        match (re.Match)199    Returns:200        str201    """202    sign = match.group(1)203    number = match.group(2)204    pure_decimal = match.group(5)205    if pure_decimal:206        result = num2str(pure_decimal)207    else:208        sign: str = "负" if sign else ""209        number: str = num2str(number)210        result = f"{sign}{number}"211    return result212 213 214# 范围表达式215# match.group(1) and match.group(8) are copy from RE_NUMBER216 217RE_RANGE = re.compile(218    r"""219    (?<![\d\+\-\×÷=])      # 使用反向前瞻以确保数字范围之前没有其他数字和操作符220    ((-?)((\d+)(\.\d+)?))  # 匹配范围起始的负数或正数(整数或小数)221    [-~]                   # 匹配范围分隔符222    ((-?)((\d+)(\.\d+)?))  # 匹配范围结束的负数或正数(整数或小数)223    (?![\d\+\-\×÷=])       # 使用正向前瞻以确保数字范围之后没有其他数字和操作符224    """, re.VERBOSE)225 226 227def replace_range(match) -> str:228    """229    Args:230        match (re.Match)231    Returns:232        str233    """234    first, second = match.group(1), match.group(6)235    first = RE_NUMBER.sub(replace_number, first)236    second = RE_NUMBER.sub(replace_number, second)237    result = f"{first}到{second}"238    return result239 240 241# ~至表达式242RE_TO_RANGE = re.compile(243    r'((-?)((\d+)(\.\d+)?)|(\.(\d+)))(%|°C|℃|度|摄氏度|cm2|cm²|cm3|cm³|cm|db|ds|kg|km|m2|m²|m³|m3|ml|m|mm|s)[~]((-?)((\d+)(\.\d+)?)|(\.(\d+)))(%|°C|℃|度|摄氏度|cm2|cm²|cm3|cm³|cm|db|ds|kg|km|m2|m²|m³|m3|ml|m|mm|s)')244 245def replace_to_range(match) -> str:246    """247    Args:248        match (re.Match)249    Returns:250        str251    """252    result = match.group(0).replace('~', '至')253    return result254 255 256def _get_value(value_string: str, use_zero: bool=True) -> List[str]:257    stripped = value_string.lstrip('0')258    if len(stripped) == 0:259        return []260    elif len(stripped) == 1:261        if use_zero and len(stripped) < len(value_string):262            return [DIGITS['0'], DIGITS[stripped]]263        else:264            return [DIGITS[stripped]]265    else:266        largest_unit = next(267            power for power in reversed(UNITS.keys()) if power < len(stripped))268        first_part = value_string[:-largest_unit]269        second_part = value_string[-largest_unit:]270        return _get_value(first_part) + [UNITS[largest_unit]] + _get_value(271            second_part)272 273 274def verbalize_cardinal(value_string: str) -> str:275    if not value_string:276        return ''277 278    # 000 -> '零' , 0 -> '零'279    value_string = value_string.lstrip('0')280    if len(value_string) == 0:281        return DIGITS['0']282 283    result_symbols = _get_value(value_string)284    # verbalized number starting with '一十*' is abbreviated as `十*`285    if len(result_symbols) >= 2 and result_symbols[0] == DIGITS[286            '1'] and result_symbols[1] == UNITS[1]:287        result_symbols = result_symbols[1:]288    return ''.join(result_symbols)289 290 291def verbalize_digit(value_string: str, alt_one=False) -> str:292    result_symbols = [DIGITS[digit] for digit in value_string]293    result = ''.join(result_symbols)294    if alt_one:295        result = result.replace("一", "幺")296    return result297 298 299def num2str(value_string: str) -> str:300    integer_decimal = value_string.split('.')301    if len(integer_decimal) == 1:302        integer = integer_decimal[0]303        decimal = ''304    elif len(integer_decimal) == 2:305        integer, decimal = integer_decimal306    else:307        raise ValueError(308            f"The value string: '${value_string}' has more than one point in it."309        )310 311    result = verbalize_cardinal(integer)312 313    decimal = decimal.rstrip('0')314    if decimal:315        # '.22' is verbalized as '零点二二'316        # '3.20' is verbalized as '三点二317        result = result if result else "零"318        result += '点' + verbalize_digit(decimal)319    return result320 321 322if __name__ == "__main__":323    324    text = ""325    text = num2str(text)326    print(text)327    pass