【问题标题】:Regex capture first/last word in a filename正则表达式捕获文件名中的第一个/最后一个单词
【发布时间】:2013-08-01 17:35:28
【问题描述】:

我的文件名可以包含任意数量的单词/空格。基本上,我需要正确的语法来消耗字符串中间的任何字符而不消耗最后一个单词。

一些问题背景- 第一个词或最后一个词可能是我需要捕捉的日期。或者,最后一个词可以是首字母。我需要命名捕获组中的日期/姓名首字母。

示例文件,

FileName                                      Expected Capture Groups
--------                                      ----------------------
Myfile 120101.xls                             Date: {Myfile, 120101}
120101 MyFile.xls                             Date: {Myfile, 120101}
MyFile BHO.doc                                Date: {Myfile} Initials: {BHO}
120101 My file name BHO.docx                  Date: {120101} Initials: {BHO}
Foo.bar                                       None    
WhyDidIUsePeriods.huh.doc                     None
120101 WhyDidIUsePeriods.huh.doc              Date: {WhyDidIUsePeriods, 120101}
WhyDidIUsePeriods BHO.huh.doc                 Date: {WhyDidIUsePeriods} Initials: {BHO}
120101 WhyDidIUsePeriods BHO.huh.doc          Date: {120101} Initials: {BHO}

到目前为止,我有以下正则表达式:

@"^(?<Date>.+?(?= ))?.*?((?<Initials>(?<= )[^0-9]*?)|(?<Date>(?<= ).*?))?\..*?$"

这适用于两个字长的文件名,但不适用于更大的文件名(尾随组捕获多个单词)。问题是第一个日期捕获组之后的.*?。我需要这个来贪婪地捕捉所有“内部”词而不消耗最后一个词。我正在考虑负前瞻,但我不确定如何构造它,以便该模式既消耗所有字符又不消耗匹配某个负前瞻模式( .*?\.) 的字符。

(日期捕获组可以捕获非日期,稍后会有自定义解析逻辑)

我想要的东西是否可以通过负面的前瞻来实现?是否有更好的策略来满足这些要求?

编辑:

我已经说明了每个文件示例旁边的预期结果。我不想要任何更具体的日期正则表达式,因为它也可能是各种非数字格式。

不幸的是,Regex 是必要的,因为在某些情况下,有问题的 .*? 将被替换为更具体的模式(例如,假设某些文件还需要包含单词“Foo”,Regex 似乎是最好的工具)。

【问题讨论】:

  • 你能从你的文件名中发布你的期望值吗?
  • 你如何定义“单词”?此外,文件名由 1 个或多个与句点 (.) 连接的 segments 组成。当您说“找到第一个和最后一个单词”时,它如何与文件名的分段结构联系起来?如果文件名由单个单词组成怎么办?
  • 可以假定文件名具有扩展名。我只关心第一段(在任何时期之前)。单词由字符串、空格或句点的开头分隔。
  • 您的示例文本并不完全一致。为什么日期与倒数第二个示例中的字符串字母匹配?
  • @Denomales 正如我所提到的,日期字段不限于数字。有时它可能是非数字字符,我稍后会对其进行解析(例如,2012Q4)。

标签: c# .net regex


【解决方案1】:

说明

这个表达式将:

  • 假设文件名中唯一感兴趣的数据存在于第一个点之前
  • 假定首字母为三个大写字母,前面有一个空格,后面是一个点
  • 捕获文件名的非首字母和非日期部分
  • 捕获整个文件名,但不包括第一个点
  • 如果存在缩写,则捕获它们
  • 捕获日期(如果存在)
  • 如果文件名中存在日期、缩写和文件,则允许它们以任意顺序出现

为此,我正在使用

^
(?=(?:[^.]*?(?<file>(?<=^)[a-zA-Z\s]*?(?=\s[A-Z]{3}\.|\s)|(?<=\s)[a-zA-Z\s]*?(?=\.|\s[A-Z]{3}\.)))?)   # get the file (aka not date and not initials
(?=(?:[^.]*?\s(?<Initials>[A-Z]{3})\.)?)      # get the initials
(?=(?:[^.]*?(?<Date>\d+))?)   # capture the date value if it exists.
(?=(?<FileName>.*?)\.)     # capture entire filename upto but not including the first dot
.*

示例

Live Demo

示例文本

Myfile 120101.xls
120101 MyFile.xls
MyFile BHO.doc
120101 My file name BHO.docx
Foo.bar
WhyDidIUsePeriods.huh.doc
120101 WhyDidIUsePeriods.huh.doc
WhyDidIUsePeriods BHO.huh.doc
120101 WhyDidIUsePeriods BHO.huh.doc

代码

Regex re = new Regex(@"^(?=(?:[^.]*?(?<file>(?<=^)[a-zA-Z\s]*?(?=\s[A-Z]{3}\.|\s)|(?<=\s)[a-zA-Z\s]*?(?=\.|\s[A-Z]{3}\.)))?)(?=(?:[^.]*?\s(?<Initials>[A-Z]{3})\.)?)(?=(?:[^.]*?(?<Date>\d+))?)(?=(?<FileName>.*?)\.).*",RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
MatchCollection mc = re.Matches(sourcestring);

匹配项

[0][0] = Myfile 120101.xls    
[0][file] = Myfile
[0][Initials] = 
[0][Date] = 120101
[0][FileName] = Myfile 120101

[1][0] = 120101 MyFile.xls    
[1][file] = MyFile
[1][Initials] = 
[1][Date] = 120101
[1][FileName] = 120101 MyFile

[2][0] = MyFile BHO.doc    
[2][file] = MyFile
[2][Initials] = BHO
[2][Date] = 
[2][FileName] = MyFile BHO

[3][0] = 120101 My file name BHO.docx
[3][file] = My file name
[3][Initials] = BHO
[3][Date] = 120101
[3][FileName] = 120101 My file name BHO

[4][0] = Foo.bar
[4][file] = Foo
[4][Initials] = 
[4][Date] = 
[4][FileName] = Foo

[5][0] = WhyDidIUsePeriods.huh.doc    
[5][file] = WhyDidIUsePeriods
[5][Initials] = 
[5][Date] = 
[5][FileName] = WhyDidIUsePeriods

[6][0] = 120101 WhyDidIUsePeriods.huh.doc    
[6][file] = WhyDidIUsePeriods
[6][Initials] = 
[6][Date] = 120101
[6][FileName] = 120101 WhyDidIUsePeriods

[7][0] = WhyDidIUsePeriods BHO.huh.doc    
[7][file] = WhyDidIUsePeriods
[7][Initials] = BHO
[7][Date] = 
[7][FileName] = WhyDidIUsePeriods BHO

[8][0] = 120101 WhyDidIUsePeriods BHO.huh.doc
[8][file] = WhyDidIUsePeriods
[8][Initials] = BHO
[8][Date] = 120101
[8][FileName] = 120101 WhyDidIUsePeriods BHO

【讨论】:

  • 谢谢。这对帮助我找到正确的解决方案非常有帮助。我以前从未见过在单独的前瞻中执行所有匹配的技术,它非常有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多