Python:将旧样式格式模式转换为新样式格式模式

scyqe7ek  于 2023-01-04  发布在  Python
关注(0)|答案(3)|浏览(133)

有没有什么“内置”的方法可以将旧样式的格式模式字符串转换成新样式的格式。或者使用好的旧正则表达式更好?
例如,我们有模式'%(a)s - %(b)s',并希望转换为'{a} - {b}'

dffbzjpn

dffbzjpn1#

没有找到任何已经构建的转换格式的int解决方案。下面是我如何使用regex实现的。

import re    

ODD_REPEAT_PATTERN = r'((?<!{c}){c}({c}{c})*(?!{c}))'
EVEN_REPEAT_PATTERN = r'(?<!{c})({c}{c})+(?!{c})'

def __to_new_format(fmt: str, named=True):
    def to_named_fmt(fmt):
        pattern = rf'{odd_perc_pattern}\((.*?)\)s'
        match = re.search(pattern, fmt)
        while match:
            # Only care about placeholder group here.
            __, __, placeholder = match.groups()
            fmt = fmt.replace(
                f'%({placeholder})s',
                f'{{{placeholder}}}'
            )
            match = re.search(pattern, fmt)
        return fmt

    def to_pos_fmt(fmt):
        even_perc_pattern = EVEN_REPEAT_PATTERN.format(c='%')
        pattern = rf'{even_perc_pattern}s'
        # When positional placeholder has even amount of percents, it
        # will be treated as not having enough arguments passed.
        if re.search(pattern, fmt):
            raise TypeError(
                'not all arguments converted during string formatting'
            )
        return fmt.replace('%s', '{}')

    odd_perc_pattern = ODD_REPEAT_PATTERN.format(c='%')
    # Escape `{` and `}`, because new formatting uses it.
    fmt = fmt.replace('{', '{{').replace('}', '}}')
    fmt = to_named_fmt(fmt) if named else to_pos_fmt(fmt)
    # If we find odd number of occurring percentage symbols, it means
    # those were not escaped and we can't finish conversion.
    if re.search(odd_perc_pattern, fmt):
        raise ValueError('incomplete format')
    return fmt.replace('%%', '%')

def to_new_named_format(fmt: str) -> str:
    """Convert old style named formatting to new style formatting.

    For example: '%(x)s - %%%(y)s' -> '{x} - %{y}'

    Args:
        fmt: old style formatting to convert.

    Returns:
        new style formatting.

    """
    return __to_new_format(fmt, named=True)

def to_new_pos_format(fmt: str) -> str:
    """Convert old style positional formatting to new style formatting.

    For example: '%s - %%%s' -> '{} - %{}'

    Args:
        fmt: old style formatting to convert.

    Returns:
        new style formatting.

    """
    return __to_new_format(fmt, named=False)
7bsow1i6

7bsow1i62#

下面是@Andrius的答案的一个变体,它被修改来处理s以外的说明符:

import re

ODD_REPEAT_PATTERN = r'((?<!{c}){c}({c}{c})*(?!{c}))'
EVEN_REPEAT_PATTERN = r'(?<!{c})({c}{c})+(?!{c})'
SPECIFIER_PATTERN = r'[^(]*[diouxXeEfFgGcs]'  # TODO: handle r

def __to_new_format(fmt: str, named=True):
    def to_named_fmt(fmt):
        pattern = rf'{odd_perc_pattern}\((.*?)\)({SPECIFIER_PATTERN})'
        match = re.search(pattern, fmt)
        while match:
            # Only care about placeholder group here.
            __, __, placeholder, specifier = match.groups()
            fmt = fmt.replace(
                f'%({placeholder}){specifier}',
                f'{{{placeholder}:{specifier}}}'
            )
            match = re.search(pattern, fmt)
        return fmt

    def to_pos_fmt(fmt):
        even_perc_pattern = EVEN_REPEAT_PATTERN.format(c='%')
        pattern = rf'{even_perc_pattern}s'
        # When positional placeholder has even amount of percents, it
        # will be treated as not having enough arguments passed.
        if re.search(pattern, fmt):
            raise TypeError(
                'not all arguments converted during string formatting'
            )
        return re.sub(
                rf"%({SPECIFIER_PATTERN})",
                lambda sub_match: f'{{:{sub_match.group(1)}}}',
                fmt
            )

    odd_perc_pattern = ODD_REPEAT_PATTERN.format(c='%')
    # Escape `{` and `}`, because new formatting uses it.
    fmt = fmt.replace('{', '{{').replace('}', '}}')
    fmt = to_named_fmt(fmt) if named else to_pos_fmt(fmt)
    # If we find odd number of occurring percentage symbols, it means
    # those were not escaped and we can't finish conversion.
    if re.search(odd_perc_pattern, fmt):
        raise ValueError('incomplete format')
    return fmt.replace('%%', '%')

def to_new_named_format(fmt: str) -> str:
    """Convert old style named formatting to new style formatting.
    For example: '%(x)s - %%%(y)s' -> '{x} - %{y}'
    Args:
        fmt: old style formatting to convert.
    Returns:
        new style formatting.
    """
    return __to_new_format(fmt, named=True)

def to_new_pos_format(fmt: str) -> str:
    """Convert old style positional formatting to new style formatting.
    For example: '%s - %%%s' -> '{} - %{}'
    Args:
        fmt: old style formatting to convert.
    Returns:
        new style formatting.
    """
    return __to_new_format(fmt, named=False)
67up9zun

67up9zun3#

你可以使用f字符串,只要确保你有python3.6+

mystring = f'{a} - {b}'

相关问题