【问题标题】:Splitting string before name of month with regex使用正则表达式在月份名称之前拆分字符串
【发布时间】:2015-06-06 23:30:49
【问题描述】:

我有一堆带有随机文本的行,每行的末尾都有一个时间戳。我试图在时间戳之前拆分这些行。

当前输出:

Yes, I'd say so. Nov 08, 2014 UTC
Hell yes! Oct 01, 2014 UTC 
Anbefalt som bare det, løp og kjøp. Sep 16, 2014 UTC
Etc.

所需的输出(“制表符”是指实际的空白):

Yes, I'd say so. <tab> Nov 08, 2014 UTC
Hell yes! <tab> Oct 01, 2014 UTC
Anbefalt som bare det, løp og kjøp. <tab> Sep 16, 2014 UTC
Etc.

到目前为止,我已经使用“替换”在月份之前放置一个制表符。像这样:

my_string.replace("May ", "\tMay ").replace("Apr ", "\tApr ").replace("Mar ", "\tMar ").replace("Feb ", "\tFeb ") etc. (incomplete code)

这很好用,除非随机文本涉及月份的名称,例如“我去年五月买的,很棒的东西”。由于日期是以这种特定方式格式化的,如果可能的话,我想用正则表达式和通配符对此进行改进。有没有办法在这些日期之前放置一个标签?如上所示,日期格式如下:

[Three-letter abbreviation of the month] [two-digit day] [,] [four-digit year] [UTC]

例如

Oct 31, 2014 UTC

请原谅业余代码和方法,我是一个绝对的正则表达式 n00b。我已经在 SO 上四处寻找答案,但我做得很短。希望有人能帮忙!

【问题讨论】:

  • 每个人都想使用正则表达式!字符串操作通常有更简单的解决方案,如下面的解决方案所示。

标签: python regex python-2.7 replace data-cleaning


【解决方案1】:

如果你总能保证它是这么多单词,那么你就不需要正则表达式,只需使用内置函数反向拆分和连接,例如:

s = "Yes, I'd say so. Nov 08, 2014 UTC"
split = s.rsplit(None, 4)
new = split[0] + '\t' + ' '.join(split[1:])
# "Yes, I'd say so.\tNov 08, 2014 UTC"

【讨论】:

  • 有意思,4指的是什么?
  • @user3343907 这是要拆分的最大数量 - 因此在这种情况下,只需拆分 4 个空白字符,然后停止,列表的第一项将保留您的文本,其余的我们重新加入空间以重建......比使用正则表达式(构建有限状态机)更快更高效
  • 这很有帮助,很高兴知道!非常感谢!
【解决方案2】:

您应该能够在所有月份使用一个 RegEx 来做到这一点:

import re

lines = [
    "Yes, I'd say so. Nov 08, 2014 UTC",
    "Hell yes! Oct 01, 2014 UTC"
]

for ln in lines:
    print re.sub(r'(\w+\s\d{2}, \d{4} UTC)$', r'\t\1', ln)

哪个会返回:

Yes, I'd say so.    Nov 08, 2014 UTC
Hell yes!   Oct 01, 2014 UTC

它的工作原理很简单。 re.sub 捕获第一个参数括号中的所有内容并将其分配给\1。第二个参数r'\t\1' 是我们要替换的字符串。

在您的情况下,您希望将其替换为原始字符串(由 \1 表示),并在其前面加上制表符 (\t)。

【讨论】:

    【解决方案3】:

    如果您想要每个月份名称的正则表达式并添加标签,请使用re.sub

    lines = """Yes, I'd say so. Nov 08, 2014 UTC
    Hell yes! Oct 01, 2014 UTC
    Anbefalt som bare det, løp og kjøp. Sep 16, 2014 UTC"""
    
    r = re.compile(r"\bJan\b|\bFeb\b|\bMar\b|\bApr\b|\bMay\b|\bJun\b|\bJul\b|\bAug\b|\bSep\b|\bOct\b|\bNov\b|\bDec\b")
    
    for line in lines.splitlines():
        print(r.sub("\t"+r"\g<0>", line))
    

    输出:

    Yes, I'd say so.    Nov 08, 2014 UTC
    Hell yes!   Oct 01, 2014 UTC
    Anbefalt som bare det, løp og kjøp.     Sep 16, 2014 UTC
    

    不管行的格式是什么,正则表达式仍然会找到任何月份的精确匹配项。

    要完全匹配月份空格数字和逗号:

    r = re.compile(r"(\bJan\b)\s+\d+,|(\bFeb\b)\s+\d+,|(\bMar\b)\s+\d+,|(\bApr\b)\s+\d+,|"
                   r"(\bMay\b)\s+\d+,|(\bJun\b)\d+,|(\bJul\b)\s+\d+,|(\bAug\b)\s+\d+,|"
                   r"(\bSep\b)\s+\d+,|(\bOct\b)\s+\d+,|(\bNov\b)\s+\d+,|(\bDec\b)\s+\d+,")
    

    【讨论】:

      【解决方案4】:

      从末尾开始分成 16 个字符

      data = """Yes, I'd say so. Nov 08, 2014 UTC
      Hell yes! Oct 01, 2014 UTC
      Anbefalt som bare det, løp og kjøp. Sep 16, 2014 UTC"""
      

      您也可以根据需要重新格式化日期。

      from datetime import datetime
          
      fmt = "%b %d, %Y %Z"
      
      for line in data.split("\n"):
          txt = line[:-16]
          dt = datetime.strptime(line[-16:], fmt)
          print("{}\t{}".format(txt, dt.strftime(fmt)))
      

      【讨论】:

      • 知道为什么我被否决了吗?我认为这个答案是正确的。如果日期格式一致,则将其简单拆分为 16 个字符。
      猜你喜欢
      • 1970-01-01
      • 2011-10-06
      • 2017-12-30
      • 2017-02-23
      相关资源
      最近更新 更多