自定义 .format() 的用户输入
User input for custom .format()
我得到了一个包含 4 个变量的元组列表,每个变量将打印在一行中,我希望用户指定这些打印的格式。
到目前为止,这是我的代码:
mylist = [
("Monday", "13", "November", "2017"),
("Tuesday", "14", "November", "2017"),
("Wednesday", "15", "November", "2017")]
# Note: The real list have a thousand of items, not just 3.
custom_format = self.GUI_field_where_user_types.get_text()
for item in mylist:
weekday = item[0]
daynumber = item[1]
month = item[2]
year = item[3]
print(eval(custom_format))
# Example custom_format: '"{0}, {1} of {2} from year {3}".format(weekday, daynumber, month, year)'
对于测试,我只是尝试了上面的输入,它显然有效,但我不想使用 eval,因为它显然太危险了。所以我的问题是:如何让用户以安全的方式定义格式?
注意: 用户应该只能编辑 .format() 方法之前的字符串 "{0}, {1} of {2} from year {3}"
,阻止访问任何 python 命令,但只允许他使用他想要的变量,而不是总是使用其中的 4 个。一些示例可能是:
- {0},{1},共 {2}
- {3},{1} 月 {2}
- {0},{3} 年 {2} 中的 {1} 个
- {1}随便{2} -- {3}
使用一种方法来排列格式:
def fill_format(custom_format, date):
used_vars = []
used_indexes = []
#Look for what is used
for i in range(len(date)):
if "{"+str(i)+"}" in custom_format:
used_vars.append(date[i])
used_indexes.append(i)
#Replace indexes starting from 0
for new_index, used_index in enumerate(used_indexes):
custom_format = custom_format.replace("{"+str(used_index)+"}", "{"+str(new_index)+"}")
return custom_format.format(*used_vars)
mylist = [
("Monday", "13", "November", "2017"),
("Tuesday", "14", "November", "2017"),
("Wednesday", "15", "November", "2017")]
custom_format = "{3}, {1} at month {2}"
for item in mylist:
print(fill_format(custom_format, item))
输出:
2017, 13 at month November
2017, 14 at month November
2017, 15 at month November
编辑:
如果一个日期总是有 4 个时间单位,您可以使用:
def fill_format(custom_format, date):
return custom_format.replace("{0}", date[0]).replace("{1}", date[1]).replace("{2}", date[2]).replace("{3}", date[3])
我的建议:坚持使用标准化的 datetime
格式。借助 datetime,我们可以使用强大的 strftime 根据一组预定义的模式打印日期时间。考虑这个例子:
import datetime
mylist = [
("Monday", "13", "November", "2017"),
("Tuesday", "14", "November", "2017"),
("Wednesday", "15", "November", "2017")]
custom_format = "%A, %d of %B from year %Y"
for item in mylist:
# Create datetime object
dt = datetime.datetime.strptime('-'.join([*item]),"%A-%d-%B-%Y")
# Print with format
print(dt.strftime(custom_format))
打印:
Monday, 13 of November from year 2017
Tuesday, 14 of November from year 2017
Wednesday, 15 of November from year 2017
如果您想创建自己的 "own language",请使用字典映射到标准字典。考虑这个例子:
import datetime
import re
mylist = [
("Monday", "13", "November", "2017"),
("Tuesday", "14", "November", "2017"),
("Wednesday", "15", "November", "2017")]
d = {"WEEKDAY": "%A",
"DAYNUMBER": "%d",
"MONTH": "%B",
"YEAR": "%Y"}
input_ = "YEAR-%m-DAYNUMBER is equal to WEEKDAY, DAYNUMBER of MONTH from year YEAR"
# Use re library to change WEEKDAY --> %A and so on...
pattern = re.compile(r'\b(' + '|'.join(d.keys()) + r')\b')
custom_format = pattern.sub(lambda x: d[x.group()], input_)
for item in mylist:
# Create datetime object
dt = datetime.datetime.strptime('-'.join([*item]),"%A-%d-%B-%Y")
# Print with format
print(dt.strftime(custom_format))
输出:
2017-11-13 is equal to Monday, 13 of November from year 2017
2017-11-14 is equal to Tuesday, 14 of November from year 2017
2017-11-15 is equal to Wednesday, 15 of November from year 2017
这以最少的代码提供了您需要的所有灵活性。
很简单。只需在输入字符串上调用 .format
,并使用参数解包语法将项目作为参数传递:
mylist = [
("Monday", "13", "November", "2017"),
("Tuesday", "14", "November", "2017"),
("Wednesday", "15", "November", "2017")]
fmt = input('Format? ')
for item in mylist:
print(fmt.format(*item))
执行:
Format? {0}, {1} of {2}
Monday, 13 of November
Tuesday, 14 of November
Wednesday, 15 of November
要处理用户输入无效的格式,您可以捕获异常并重试:
while True:
try:
fmt = input('Format? ')
for item in mylist:
print(fmt.format(*item))
break
except (IndexError,ValueError,KeyError):
print('Invalid format.')
执行:
Format? {A}
Invalid format.
Format? {4}
Invalid format.
Format? {
Invalid format.
Format? The year is {3}
The year is 2017
The year is 2017
The year is 2017
我得到了一个包含 4 个变量的元组列表,每个变量将打印在一行中,我希望用户指定这些打印的格式。
到目前为止,这是我的代码:
mylist = [
("Monday", "13", "November", "2017"),
("Tuesday", "14", "November", "2017"),
("Wednesday", "15", "November", "2017")]
# Note: The real list have a thousand of items, not just 3.
custom_format = self.GUI_field_where_user_types.get_text()
for item in mylist:
weekday = item[0]
daynumber = item[1]
month = item[2]
year = item[3]
print(eval(custom_format))
# Example custom_format: '"{0}, {1} of {2} from year {3}".format(weekday, daynumber, month, year)'
对于测试,我只是尝试了上面的输入,它显然有效,但我不想使用 eval,因为它显然太危险了。所以我的问题是:如何让用户以安全的方式定义格式?
注意: 用户应该只能编辑 .format() 方法之前的字符串 "{0}, {1} of {2} from year {3}"
,阻止访问任何 python 命令,但只允许他使用他想要的变量,而不是总是使用其中的 4 个。一些示例可能是:
- {0},{1},共 {2}
- {3},{1} 月 {2}
- {0},{3} 年 {2} 中的 {1} 个
- {1}随便{2} -- {3}
使用一种方法来排列格式:
def fill_format(custom_format, date):
used_vars = []
used_indexes = []
#Look for what is used
for i in range(len(date)):
if "{"+str(i)+"}" in custom_format:
used_vars.append(date[i])
used_indexes.append(i)
#Replace indexes starting from 0
for new_index, used_index in enumerate(used_indexes):
custom_format = custom_format.replace("{"+str(used_index)+"}", "{"+str(new_index)+"}")
return custom_format.format(*used_vars)
mylist = [
("Monday", "13", "November", "2017"),
("Tuesday", "14", "November", "2017"),
("Wednesday", "15", "November", "2017")]
custom_format = "{3}, {1} at month {2}"
for item in mylist:
print(fill_format(custom_format, item))
输出:
2017, 13 at month November
2017, 14 at month November
2017, 15 at month November
编辑:
如果一个日期总是有 4 个时间单位,您可以使用:
def fill_format(custom_format, date):
return custom_format.replace("{0}", date[0]).replace("{1}", date[1]).replace("{2}", date[2]).replace("{3}", date[3])
我的建议:坚持使用标准化的 datetime
格式。借助 datetime,我们可以使用强大的 strftime 根据一组预定义的模式打印日期时间。考虑这个例子:
import datetime
mylist = [
("Monday", "13", "November", "2017"),
("Tuesday", "14", "November", "2017"),
("Wednesday", "15", "November", "2017")]
custom_format = "%A, %d of %B from year %Y"
for item in mylist:
# Create datetime object
dt = datetime.datetime.strptime('-'.join([*item]),"%A-%d-%B-%Y")
# Print with format
print(dt.strftime(custom_format))
打印:
Monday, 13 of November from year 2017
Tuesday, 14 of November from year 2017
Wednesday, 15 of November from year 2017
如果您想创建自己的 "own language",请使用字典映射到标准字典。考虑这个例子:
import datetime
import re
mylist = [
("Monday", "13", "November", "2017"),
("Tuesday", "14", "November", "2017"),
("Wednesday", "15", "November", "2017")]
d = {"WEEKDAY": "%A",
"DAYNUMBER": "%d",
"MONTH": "%B",
"YEAR": "%Y"}
input_ = "YEAR-%m-DAYNUMBER is equal to WEEKDAY, DAYNUMBER of MONTH from year YEAR"
# Use re library to change WEEKDAY --> %A and so on...
pattern = re.compile(r'\b(' + '|'.join(d.keys()) + r')\b')
custom_format = pattern.sub(lambda x: d[x.group()], input_)
for item in mylist:
# Create datetime object
dt = datetime.datetime.strptime('-'.join([*item]),"%A-%d-%B-%Y")
# Print with format
print(dt.strftime(custom_format))
输出:
2017-11-13 is equal to Monday, 13 of November from year 2017
2017-11-14 is equal to Tuesday, 14 of November from year 2017
2017-11-15 is equal to Wednesday, 15 of November from year 2017
这以最少的代码提供了您需要的所有灵活性。
很简单。只需在输入字符串上调用 .format
,并使用参数解包语法将项目作为参数传递:
mylist = [
("Monday", "13", "November", "2017"),
("Tuesday", "14", "November", "2017"),
("Wednesday", "15", "November", "2017")]
fmt = input('Format? ')
for item in mylist:
print(fmt.format(*item))
执行:
Format? {0}, {1} of {2}
Monday, 13 of November
Tuesday, 14 of November
Wednesday, 15 of November
要处理用户输入无效的格式,您可以捕获异常并重试:
while True:
try:
fmt = input('Format? ')
for item in mylist:
print(fmt.format(*item))
break
except (IndexError,ValueError,KeyError):
print('Invalid format.')
执行:
Format? {A}
Invalid format.
Format? {4}
Invalid format.
Format? {
Invalid format.
Format? The year is {3}
The year is 2017
The year is 2017
The year is 2017