【问题标题】:regex month replacement MM-DD-YYYY to 'month_string DD, YYYY' [closed]正则表达式月份替换 MM-DD-YYYY 到 'month_string DD, YYYY' [关闭]
【发布时间】:2021-10-19 12:31:23
【问题描述】:

我在 python 中工作:

我正在尝试在不使用 excel 的情况下转换 csv 文件中的列,只使用正则表达式。

month_dictionary={"January":1,
"February":2, 
"March":3, 
#...etc

这是我目前所拥有的。

with open(file, newline="") as csvfile:
    reader = csv.reader(csvfile, delimiter=",", quotechar='"')
    for row in reader:
        for item in row:
            item.replace(r"(\d{1,2})\/(\d{1,2})\/(\d{4})/gm", month_dictionary[r"${1}"], r"${2}, ${3}")

我不太了解正则表达式,我在谷歌上搜索时遇到了一些麻烦。

我得到的错误是:

KeyError: '${1}'

那么如何正确格式化替换正则表达式以执行我想要的操作?

05-25-1999
into
May 25, 19999

我希望这是一个简单的问题,与我对格式的无知有关。

【问题讨论】:

  • 出于兴趣,您是否有理由不使用 ISO 8601 格式?
  • str.replace() 不处理正则表达式,需要使用re.sub()。解决方法是用一个函数作为替换,它可以做字典查找。
  • @PranavHosangadi 冷静一下,OP 只是想给出完整的上下文。我认为这个问题不值得一票否决。
  • 但是为什么要使用正则表达式而不是 datetime 库呢?
  • @JamesGeddes 完整上下文在干扰 MRE 的可重复性时没有帮助。

标签: python regex csv date


【解决方案1】:

James 已经使用 python 的内置 datetime 模块添加了一个 answer,但是如果您仍想使用正则表达式(例如,如果这是学习正则表达式的练习),那么您的方法出现了一些问题:

  1. 您的正则表达式与您的输入字符串不匹配:您正在尝试匹配一个连字符分隔的日期,您的正则表达式是正斜杠分隔的。你需要r"(\d{1,2})-(\d{1,2})-(\d{4})"。
  2. 在python中,正则表达式匹配组使用\1、\2等引用,而不是${1}、${2}。
  3. 您需要使用re.sub() 替换为正则表达式,而不是str.replace()。
  4. 您的month_dictionary 倒退了。您需要使用月份编号而不是月份名称进行查找,因此您的字典的键必须是月份编号。如果您已经有month_dictionary 并且不想手动写出相反的内容,您可以通过简单的字典理解来完成:
month_num_dict = {num: name for name, num in month_dictionary.items()}
  1. 在执行re.sub() 时不能从字典中查找。替换字符串必须是正则表达式引擎可以理解的内容,因此它只能是常量字符串或使用组的字符串,或者采用match 对象的函数。 https://docs.python.org/3/library/re.html#re.sub

现在,让我们使用re.sub() 的能力来获取一个返回替换字符串的函数。

item = '05-25-1999'
rexp = r"(\d{1,2})-(\d{1,2})-(\d{4})"

def make_repl(match_obj):
    # Get the first group and convert to int
    month_num = int(match_obj.group(1)) 
    # Get month name from lookup
    month_name = month_num_dict[month_num] 
    # Format month name and other groups into the replacement string
    return f"{month_name} {match_obj.group(2)}, {match_obj.group(3)}" 

item_mod = re.sub(rexp, make_repl, item)
print(item_mod)

这给了我们我们需要的东西:

May 25, 1999

【讨论】:

    【解决方案2】:

    人类进行日期时间的方式是ridiculous,因此混淆是可以理解的 (IMO)。

    我也希望你不要介意我在这里没有使用正则表达式,因为 python 可以自己做到这一点。

    from datetime import datetime
    
    datetime_str_in = "04-03-2002"
    
    datetime_in = datetime.strptime(datetime_str_in, "%m-%d-%Y")
    datetime_out = datetime_in.strftime("%B %d, %Y")
    
    print(datetime_in)
    print(datetime_out)
    

    输出:

    2002-04-03 00:00:00
    April 03, 2002
    

    也可以在一行中(有效地)执行此操作,但可以说是以牺牲一点可读性为代价。

    from datetime import datetime
    
    datetime_str = "04-03-2002"
    
    datetime_out = datetime.strptime(datetime_str, "%m-%d-%Y").strftime("%B %d, %Y")
    
    print(datetime_out)
    

    如果我们有以下示例 CSV;

    Date,Metric
    02-03-2002,1
    05-04-2003,2
    06-07-2004,3
    

    完整的 Pythonic 解决方案如下。

    from datetime import datetime
    import csv
    
    in_file = "datetest.csv"
    out_file = "out.csv"
    
    out_row = ["Date", "Metric"]
    
    with open(out_file, "w", newline="") as csv_out:
        writer = csv.writer(csv_out)
        with open(in_file, "r", newline="") as csv_in:
            reader = csv.reader(csv_in, delimiter=",", quotechar='"')
            print(reader)
            writer.writerow(out_row)
            out_row = []
            for row in enumerate(reader):
                datetime_out = ""
                if row[0] == 0:
                    pass
                else:
                    for item in row[1]:
                        try:
                            datetime_out = datetime.strptime(item, "%m-%d-%Y").strftime("%B %d, %Y")
                            out_row.append(datetime_out)
    
                        except TypeError:
                            print("Type error")
                            out_row.append(item)
    
                        except ValueError:
                            print("Value error")
                            out_row.append(item)
                if out_row:
                    writer.writerow(out_row)
    

    正如我在评论中提到的,为了清楚起见,我强烈建议ISO 8601。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-10
      • 2012-11-20
      • 2013-08-31
      • 2011-07-11
      • 2015-01-25
      • 1970-01-01
      相关资源
      最近更新 更多