查找正则表达式以获取具有文件扩展名的子字符串



字符串有几种变体:

  1. "txt files `(*.txt)|*.txt|All files (*.*)|*.*`"
  2. "Image Files`|*.jpg;*.jpeg;*.png;`"
  3. "Excel Files `(*.xls, *.xlsx)|*.xls;*.xlsx|CSV Files (*.csv)|*.csv`"

子字符串可以以任何字符(space, ',', '.', '|', ';') -结尾,这无关紧要。

尝试了以下选项:;[^*].{3,4}(.?);", "[^*]+.(.?);";。

我需要一个正则表达式来获得string[] = {.jpg, .jpeg, ...},最好没有重复元素。

您真的需要正则表达式吗?

首先,如果按|分割,结果中的每个奇数条目都是一个扩展列表。然后,您可以通过;再次拆分以获得扩展,然后可以将扩展展平为单个序列,并修剪起始*的每个元素。最后,获取其不同的集合,并将其放入一个数组中。

这一切都可以用Split和Linq:来实现

var extensions = filter.Split('|', StringSplitOptions.RemoveEmptyEntries)
.Where((x, i) => i % 2 != 0)
.SelectMany(x => x.Split(';', StringSplitOptions.RemoveEmptyEntries))
.Select(x => x.TrimStart('*'))
.Distinct()
.ToArray();

从拆分中删除空条目可以确保如果以分隔符结束,它将被忽略。

在.NET Fiddle上查看它的实际操作。

简单拆分

我想我也会用Split来做,应该可以这样做:

str.Split('*',';','|')
.Where(s => s.StartsWith(".") && s[1..].All(Char.IsLetterOrDigit))
.Distinct();

注:这并没有对延期的长度做出任何坚持。如果你愿意,你可以在Where中添加一些内容,例如:

&& s.Length is >3 and <6

一个3或4长度的延长线与点的长度在4和5之间;大于3且小于6〃;来自。请注意,它使用了模式匹配,这是最近添加的c#。如果你的c#比较老,你需要一些老式的长度检查。。


Regex

但作为Regex的学习机会,使用捕获组从字符串中提取文件扩展名更容易

var r = new Regex(@"*(?<x>.w{3,4})b");
var arr = r.Matches()
.Cast<Match>()
.Select(m => m.Groups["x"].Value)
.Distinct();

Regex本身查找一个文本*,然后开始用(?<x>将字符捕获到一个名为x的组中。捕获的字符是:一个文字点,后面跟着3到4个单词字符(a-z,0-9)。我选择了3和4,因为您的代码选择了这一点,但请注意,扩展可能会更少或更多,所以您可以对此进行调整。Regex的最后一位要求在3或4个字符后有一个单词边界b,因为我们不希望扩展名的部分匹配超过4个字符。单词边界意味着扩展在的3或4个字符之后完成(下一个字符是非单词字符)

要使用LINQ从中提取数据,我们必须执行类似Cast的操作,将生成的集合条目转换为Match;它们已经是Matches了,但MatchCollection没有实现IEnumerable<T>,因为它很旧,所以它不兼容LINQ,除非我们做一些像Cast这样的事情来实现它。

Select从捕获组中检索字符串值,该组是.xxx扩展,Distinct删除重复的


您的Regex

至于为什么你的尝试没有奏效:

[^*]
.{3,4}
(.?)
;

这与匹配

  • char,它是除星号之外的任何字符
  • 然后是3或4个任何炭
  • 然后是捕获到未命名组中的任何字符中的零个或一个
  • 后跟分号">

在某些情况下,它可能会被调整以工作,但它似乎没有指定您正在寻找的字符模式

[^*]+
.  
(.?)
;

这与匹配

  • 一个或多个字符,该字符是除星号之外的任何字符
  • 然后是任何炭
  • 然后是捕获到未命名组中的任何字符中的零个或一个
  • 后跟分号">

我怀疑你认为^是一个允许匹配字面*的转义符-转义符是

当CCD_ 23用作CCD_;除";所以在我怀疑你试图匹配一个字面上的星号的地方,你实际上匹配了完全相反的

事实上,大多数字符在放置在字符类中时都会失去其特殊意义,因此CCD_;匹配文字星号";就像*

您的示例字符串似乎由括号之间的可选前导部分组成,后跟管道|,然后是扩展名。

如果要匹配数据的格式,可以使用具有相同名称的捕获组和group.Captures属性。

b[fF]ilesb[^*()]*(?:([^()]*))?|*(?<ext>.[w*]+)(?:[,;]*(?<ext>.[w*]+))*

在某些部分,模式匹配:

  • b[fF]ilesb匹配文件或文件
  • [^*()]*可选匹配除*()之外的任何字符
  • (?:([^()]*))?(可选)匹配括号之间的部分
  • |*匹配|*
  • (?<ext>.[w*]+)命名组ext,匹配.和单词char或*的1+倍
  • (?:非捕获组
    • [,;]*先匹配,;,然后匹配*
    • (?<ext>.[w*]+)ext的模式相同
  • )*关闭非捕获组,并可选择重复以获取所有扩展

查看C#regex 101演示和C#演示。

例如

string pattern = @"b[fF]ilesb[^*()]*(?:([^()]*))?|*(?<ext>.[w*]+)(?:[,;]*(?<ext>.[w*]+))*";    
string input = @"txt files `(*.txt)|*.txt|All files (*.*)|*.*`
Image Files`|*.jpg;*.jpeg;*.png;`
Excel Files `(*.xls, *.xlsx)|*.xls;*.xlsx|CSV Files (*.csv)|*.csv`";
var strings = Regex.Matches(input, pattern)
.SelectMany(m => m.Groups["ext"].Captures.Select(c => c.Value))
.ToArray()
.Distinct();
foreach (var s in strings)
{
Console.WriteLine(s);
}

输出

.txt
.*
.jpg
.jpeg
.png
.xls
.xlsx
.csv

另一种与数据格式无关的较短模式,匹配一个点和3或4个单词字符或星号,并在左侧断言一个点:

(?<=*).(?:w{3,4}b|*)

请参阅另一个regex演示。

最新更新