我正在处理一个数据集,需要在其中提取所有可用日期。日期可以采用以下格式:
04/20/2009; 04/20/09; 4/20/09; 4/3/09
Mar-20-2009; Mar 20, 2009; March 20, 2009; Mar. 20, 2009; Mar 20 2009;
20 Mar 2009; 20 March 2009; 20 Mar. 2009; 20 March, 2009
Mar 20th, 2009; Mar 21st, 2009; Mar 22nd, 2009
Feb 2009; Sep 2009; Oct 2010
6/2008; 12/2009
2009; 2010
我编写了以下代码:
df['dates'] = df['text'].str.extract(r'((?:\d{1,2}[/ ])?(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec[a-z.,]*[- ])?(?:\d{1,2}[a-z-, /]{1,4})?(?:\d{2,4}))')
它给了我正确的结果,除了一些文本,例如:
TEXT OUTPUT
Lab: B12 969 2007\n 12 969 #should give 2007
for 35 years, sold in 1985\n 35 #should give 1985
x 14 yrs who died i... 14 #should not be considered
我尝试将提取代码更改为
r'((?:\d{1,2}[/ ])?(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec[a-z.,]*[- ])?(?:\d{1,2}[a-z-, ]{1,4})?(?:[/]\d{2})?(?:\d{4})?)'
但是整个结果变得很糟糕
最佳答案
正则表达式的问题在于它的组成部分都是可选的,并且它匹配实际上与日期无关的数字。您需要构建一个包含强制部分的正则表达式,以避免匹配任意部分。
这很棘手:示例输入中有不同类型的日期。对于这些输入,我建议:
(?<!\d)((?<!\d[ \t])(?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?)(?:-\d{1,2}-\d{4}|(?:\.?\s*\d{1,2}(?:st|[rn]d|th)?,?)?\s*\d{4})|\d{1,2}\s+(?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?)\.?,?\s*\d{4}|(?:\d{1,2}/)?\d{1,2}/\d{2}(?:\d{2})?|(?:19|20)\d{2})(?!\d)
请参阅regex demo 。它匹配:
-
(?<!\d)
- 负向后查找:当前位置的左侧不允许有任何数字 -
(
- 外部捕获组的开始(.str.extract
必需的)-
(?<!\d[ \t])
- 当前位置左侧不允许有数字后跟空格或制表符 -
(?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?)
- 月份名称及其缩写 -
(?:-\d{1,2}-\d{4}|(?:\.?\s*\d{1,2}(?:st|[rn]d|th)?,?)?\s*\d{4})
- 两种选择之一:-
-\d{1,2}-\d{4}
--
, 1 或 2 位数字,-
然后是 4 位数字 -
|
- 或 -
(?:\.?\s*\d{1,2}(?:st|[rn]d|th)?,?)?
- 可选的非捕获组,匹配 1 或 0 次出现: -
\.?
- 可选.
-
\s*
- 0+ 空格 -
\d{1,2}
- 1 或 2 位数字 -
(?:st|[rn]d|th)?
- 可选的字符序列:st
,r
或n
随后是d
,或th
-
,?
- 可选的逗号 -
\s*\d{4}
- 0+ 个空格,然后是 4 位数字
-
-
-
|
- 或者-
\d{1,2}\s+
- 1 或 2 位数字,然后 1 个以上空格 -
(?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?)
- 月份名称及其缩写(同上) -
\.?
- 可选点 -
,?
- 可选的逗号 -
\s*
- 0+ 空格 -
\d{4}
- 四位数字
-
-
|
- 或者-
(?:\d{1,2}/)?
- 1 或 2 位数字的可选序列,然后/
-
\d{1,2}
- 1 或 2 位数字 -
/
-/
-
\d{2}(?:\d{2})?
- 2 位数字和可选的 2 位数字序列(允许 2 或 4 位数字,但不允许 3 位)
-
-
|
- 或者-
(?:19|20)
-19
或20
-
\d{2}
- 两位数
-
-
)
- 计算机捕获组结束 -
(?!\d)
- 负向前视:当前位置右侧不允许有任何数字。
在 Python 中,您可以为模式定义 block 并动态构建它:
months = r'(?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?)'
pattern = rf'(?<!\d)((?<!\d[ \t]){months}(?:-\d{{1,2}}-\d{{4}}|(?:\.?\s*\d{{1,2}}(?:st|[rn]d|th)?,?)?\s*\d{{4}})|\d{{1,2}}\s+{months}\.?,?\s*\d{{4}}|(?:\d{{1,2}}/)?\d{{1,2}}/\d{{2}}(?:\d{{2}})?|(?:19|20)\d{{2}})(?!\d)'
关于python - 从数据集中提取文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58753774/