问题最初发布在这里:用Python解析和清理存储时间的文本块。
给定以下多行字符串:
"""Hours
Monday 9:30 AM - 9:00 PM
Tuesday 9:30 AM - 9:00 PM
Wednesday 9:30 AM - 9:00 PM
Thursday 9:30 AM - 9:00 PM
Friday 9:30 AM - 11:00 PM
Saturday 9:30 AM - 11:00 PM
Sunday 11:00 AM - 6:00 PM
Holiday Hours
Thanksgiving Day 11:00 AM - 6:00 PM"""将连续工作日按工作时间分组,产生以下输出:
"""Mon-Thu 9:30AM-9:00PM
Fri-Sat 9:30AM-11:00PM
Sun & Hol 11:00AM-6:00PM"""我的方法基于解析工作日的行,按照第一个空格拆分,然后使用itertools.groupby()对每一行的第二项进行排序,使用groupby的S实现细节--它只将连续的匹配组合在一起:
from itertools import groupby
from operator import itemgetter
data = """Hours
Monday 9:30 AM - 9:00 PM
Tuesday 9:30 AM - 9:00 PM
Wednesday 9:30 AM - 9:00 PM
Thursday 9:30 AM - 9:00 PM
Friday 9:30 AM - 11:00 PM
Saturday 9:30 AM - 11:00 PM
Sunday 11:00 AM - 6:00 PM
Holiday Hours
Thanksgiving Day 11:00 AM - 6:00 PM"""
# filter relevant rows with weekdays only
rows = [row.split(" ", 1) for row in data.splitlines()[1:-2]]
# group consecutive days by a time range
result = []
for time_range, group in groupby(rows, key=itemgetter(1)):
days_in_group = [item[0] for item in group]
first_day, last_day = days_in_group[0][:3], days_in_group[-1][:3]
range_end = "-" + str(last_day) if first_day != last_day else ""
result.append("{begin}{end} {time_range}".format(begin=first_day,
end=range_end,
time_range=time_range))
print("\n".join(result))这是解决这个问题的最优方案吗?是毕多尼吗?在代码质量方面,您会改进什么?
发布于 2017-09-09 00:06:55
在输出中获得& Hol很难以任何合理的方式以编程的方式实现,没有硬编码的特殊情况。我看你并没有试图满足这部分要求。因此,规范是开放的解释。我要说的是,一个合理的方法是,如果这条线看起来像一周中的一天,就尝试解析它的开放时间,如果该行包含其他内容,则通过输出。
对于解析,我将使用正则表达式。如果使用命名捕获组,可以避免神秘的表达式,如.split()、itemgetter(1)和days_in_group[0][:3]。
而不是.append(),我把它写成一个生成器函数。
from itertools import groupby
from operator import itemgetter
import re
def group_by_hours(s):
REGEX = re.compile(r'^(?P<day_abbrev>\w{3})\w*day (?P<hours>.* - .*)|'
r'^(?P<misc>.*)', re.MULTILINE)
for hours, lines in groupby(REGEX.finditer(s), itemgetter('hours')):
lines = list(lines)
if not hours:
for line in lines:
yield line['misc']
elif len(lines) == 1:
yield "{0} {1}".format(lines[0]['day_abbrev'], hours)
elif len(lines) > 1:
yield "{0}-{1} {2}".format(lines[0]['day_abbrev'],
lines[-1]['day_abbrev'],
hours)
print('\n'.join(group_by_hours(data)))发布于 2017-09-08 22:27:07
在……里面
rows = [row.split(" ", 1) for row in data.splitlines()[1:-2]]1和-2的魔术数字有点麻烦。也许你想要创建一个发电机,它知道如何抑制“小时”,并且在“假日时间”之后不会产生更多的行。
另外,
first_day, last_day = days_in_group[0][:3], days_in_group[-1][:3]有一些神奇的数字,但可以说它们更有意义。您可以使用yield day[:3], time_range让您的生成器负责日解析。
在字符串格式中,您选择将first_day重命名为begin,将range_end重命名为end。我想我的建议是“不要那样做”。或者,如果您喜欢这些变量的名称,请始终使用该名称。
在……里面
days_in_group = [item[0] for item in group]标识符item有点模糊。pair会更好(如果您倾向于冗长的话,也可能是day_range )。
您使用rows和其他标识符污染了顶级命名空间。您的文件不能通过import重用。请使用
if __name__ == '__main__':成语是将这些代码行隐藏在def main():或类似的代码下面。
总体来说,是的,这是明智的代码,合二为一,合二为一。
https://codereview.stackexchange.com/questions/175156
复制相似问题