簡體   English   中英

R中日期的正則表達式

[英]Regular expression for dates in R

我正在嘗試在R中創建一個正則表達式,以在某些文本中搜索日期。 由於我無法控制實際的日期格式,因此我試圖“捕獲”所有可能的dd / mm / yy格式(一個或兩位數的月份,兩位或四位的年份,可選的一位或兩位的日期以及一系列分隔符) (“ /”,“-”,“。”),可能包含空格)。

到目前為止,我的正則表達式是:

pattern = "(\\d{0,2}[/\\.-])?[ ]?(\\d{1,2}[ ]*[/\\.-]|January|February|March|April|May|June|July|August|September|October|November|December|Jan|Feb|Febr|Mar|Apr|Jun|Jul|Aug|Sept|Sep|Oct|Nov|Dec|Jan\\.|Feb\\.|Febr\\.|Mar\\.|Apr\\.|Jun\\.|Jul\\.|Aug\\.|Sept\\.|Sep\\.|Oct\\.|Nov\\.|Dec\\.)[ ]*[']?\\d{2,4}"

這似乎適用於大多數格式,但是它包含一個我很難理解的錯誤:

str_extract_all("09/11 /1985", pattern = pattern) # returns: "09/11 /1985"
str_extract_all(" 09/11 /1985", pattern = pattern) # returns: c("09/11",  "1985")

這聽起來很奇怪。 由於我不包括環顧四周,因此開始時的額外空間應該沒有影響。 結果不然。 我究竟做錯了什么?

問題出在正則表達式的第一部分,您可能會嘗試匹配日期: (\\\\d{0,2}[/\\\\.-])?[ ]? 您可以選擇匹配0到2天,然后匹配其中一個定界符。 然后可以選擇匹配一個空格。

09/11 /1985 9月11日的情況下,此部分與前導空格匹配,因此將09匹配為月,將11匹配為年。

要擺脫這種行為,您應該將空格移到可選組中。 您可能還希望匹配1或2位數字,否則它將匹配前導定界符。

因此,我會將第一部分重寫為(\\\\d{1,2}[/\\\\.-][ ]?)?

您還可以改善其他幾點,例如:

  • January|Jan|Jan\\\\. Jan(?:\\\\.|uary)?
  • 考慮使用非捕獲組

我認為最好的辦法是在讀取文件之前先了解給定字符串中使用的日期格式,然后測試日期格式是否始終符合預期。 但是,正如OP所述,情況並非如此。 這不是日期格式的詳盡列表,但應該給您一種印象,即找出僅允許有效日期的正則表達式可能是一件繁瑣的工作。 另外,格式猜測可能會使不了解細節的人難以預測您的腳本。

如果您仍然認為您需要對不同的日期格式使用正則表達式,請嘗試以一種易於讀者理解的方式設計正則表達式:

(?:format1)|(?:format2)|...|(?:formatN)

在這種情況下,format1的優先級高於

https://stackoverflow.com/a/15504877/6018688上也有相當不錯的正則表達式,即使對checking年dd/mm/yyyydd-mm-yyyydd.mm.yyyy計算,它們也可以很好地檢查這些格式的日期有效性。 dd.mm.yyyy

^(?:(?:31(\\/|-|\\.)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)(\\/|-|\\.)(?:0?[1,3-9]|1[0-2])\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:29(\\/|-|\\.)0?2\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\\d|2[0-8])(\\/|-|\\.)(?:(?:0?[1-9])|(?:1[0-2]))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$

在同一個問題中,使用月名稱的不同答案:

^(?:(?:31(\\/|-|\\.)(?:0?[13578]|1[02]|(?:Jan|Mar|May|Jul|Aug|Oct|Dec)))\\1|(?:(?:29|30)(\\/|-|\\.)(?:0?[1,3-9]|1[0-2]|(?:Jan|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:29(\\/|-|\\.)(?:0?2|(?:Feb))\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\\d|2[0-8])(\\/|-|\\.)(?:(?:0?[1-9]|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep))|(?:1[0-2]|(?:Oct|Nov|Dec)))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$

我認為您現在已經有了印象,編寫一個實際上可以完成您打算做的事情的正則表達式是多么令人費解。 我真的會盡量將允許的日期保持在最低限度,並尋求一個限制性很強的正則表達式。 在您的示例中,您只給出了僅包含日期(和空格)的字符串,而沒有其他內容。 如果是這種情況,則應嘗試使用"^yourregex$"對整個字符串進行數學運算,如果要在字符串的開頭和結尾"^\\s*yourregex\\s*$"空格,請使用"^\\s*yourregex\\s*$" 由於您在字符串的開頭有一個帶空格的示例,因此我將使用后者進行進一步的開發。

在您的情況下,我將僅以幾年開始:

"^\\\\s*(?:\\\\d{4})\\\\s*$"

然后允許使用其他東西mm-dd-YY(不檢查它是否確實是有效日期或“ 33-13-2016”,但也可以使用兩位數的年份)

"(?:\\\\d{1,2}[/.-]\\\\d{1,2}[/.-](?:\\\\d{4}|\\\\d{2})"

如果要在定界符之間留出空間:

"(?:\\\\d{1,2}\\\\s*[/.-]\\\\s*\\\\d{1,2}\\\\s*[/.-]\\\\s*\\\\d{4})"

然后使用書面或縮寫月份名稱進行格式化:

"(\\\\d{1,2}\\\\s*[/.-]?\\\\s*(?:January|February|March|April|May|June|July|August|September|October|November|December|Jan|Feb|Febr|Mar|Apr|Jun|Jul|Aug|Sept|Sep|Oct|Nov|Dec|Jan\\\\.|Feb\\\\.|Febr\\\\.|Mar\\\\.|Apr\\\\.|Jun\\\\.|Jul\\\\.|Aug\\\\.|Sept\\\\.|Sep\\\\.|Oct\\\\.|Nov\\\\.|Dec\\\\.)\\\\s*[/.-]?\\\\s*(?:'?\\\\d{2}|\\\\d{4}))"

放在一起:

"^\\\\s*(?:\\\\d{4}$)|(?:\\\\d{1,2}\\\\s*[/.-]\\\\s*\\\\d{1,2}\\\\s*[/.-]\\\\s*\\\\d{4})|(\\\\d{1,2}\\\\s*[/.-]?\\\\s*(?:January|February|March|April|May|June|July|August|September|October|November|December|Jan|Feb|Febr|Mar|Apr|Jun|Jul|Aug|Sept|Sep|Oct|Nov|Dec|Jan\\\\.|Feb\\\\.|Febr\\\\.|Mar\\\\.|Apr\\\\.|Jun\\\\.|Jul\\\\.|Aug\\\\.|Sept\\\\.|Sep\\\\.|Oct\\\\.|Nov\\\\.|Dec\\\\.)\\\\s*[/.-]?\\\\s*(?:'?\\\\d{2}|\\\\d{4}))\\\\s*$"

這樣,您可以根據需要鏈接任意多種格式。

請將以下正則表達式與您的正則表達式進行比較,以檢查不同輸入字符串上的行為。 我添加了字邊界\\b約束,因為您使用了str_extract_all,所以我認為同一字符串中可以有多個日期。

string = "only a year 1985. No space 2.Jan.2016. 2. Jan. 2016. 2. Jan. '16 2/1/16 02/01/2016 19855 ID1985A 2. Jan 2016   2.. Jan 2016 1January2016 2-Jan.-2016 2-Jan-2016 2.\tJan.\t2016"
pattern = "(\\d{1,2}[/\\.-][ ]?)?(\\d{1,2}[ ]*[/\\.-]|January|February|March|April|May|June|July|August|September|October|November|December|Jan|Feb|Febr|Mar|Apr|Jun|Jul|Aug|Sept|Sep|Oct|Nov|Dec|Jan\\.|Feb\\.|Febr\\.|Mar\\.|Apr\\.|Jun\\.|Jul\\.|Aug\\.|Sept\\.|Sep\\.|Oct\\.|Nov\\.|Dec\\.)[ ]*[']?\\d{2,4}"
p="\\s*(?:\\b\\d{4}\\b)|(?:\\b\\d{1,2}\\s*[/\\.-]\\s*\\d{1,2}\\s*[/\\.-]\\s*(?:\\d{4}|\\d{2})\\b)|\\b\\d{1,2}\\s*[/\\.-]?\\s*(?:January|February|March|April|May|June|July|August|September|October|November|December|(?:Jan|Feb|Febr|Mar|Apr|Jun|Jul|Aug|Sept|Sep|Oct|Nov|Dec).?)\\s*[/\\.-]?\\s*(?:\\d{4}|'?\\d{2})\\b\\s*"
str_extract_all(string, pattern=pattern)
str_extract_all(string, pattern=p)

一個警告:當允許帶有空格的不同格式的多個版本時,您將允許難以保證僅日期匹配且文本中不包含其他數字值的差異。

不需要在字符組中轉義點,因為[\\。]中的點只能是[。]; 除非您還希望以反斜杠作為day \\ mont \\ year之間的分隔符。 當輸入格式可變時,空格也可以是\\t制表符,因此用\\s替換[ ] (匹配除\\n等行終止符之外的任何空格字符)似乎是一個好主意。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM