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)
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)
3条答案
按热度按时间dffbzjpn1#
没有找到任何已经构建的转换格式的int解决方案。下面是我如何使用regex实现的。
7bsow1i62#
下面是@Andrius的答案的一个变体,它被修改来处理
s
以外的说明符:67up9zun3#
你可以使用f字符串,只要确保你有python3.6+