查找正则表达式以获取具有文件扩展名的子字符串
Find a regular expression to get substrings with file extensions
字符串有多种变体:
"txt files `(*.txt)|*.txt|All files (*.*)|*.*`"
"Image Files`|*.jpg;*.jpeg;*.png;`"
"Excel Files `(*.xls, *.xlsx)|*.xls;*.xlsx|CSV Files (*.csv)|*.csv`"
子字符串可以以任何字符结尾(space, ',', '.', '|', ';') -
没关系。
尝试了以下选项:“[^*].{3,4}(.?);", "[^*]+.(.?);
”。
我需要一个正则表达式来得到string[] = {.jpg, .jpeg, ...}
,最好没有重复的元素。
你真的需要正则表达式吗?
首先,如果您按 |
拆分,结果中的每个奇数条目都是一个扩展名列表。然后,您可以将 再次 拆分为 ;
以获得扩展,然后您可以将其展平为单个序列和 trim 起始 [=13] 的每个元素=].最后,获取不同的集合并将其放入数组中。
这一切都可以用 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 的机会,使用捕获组更容易从字符串中提取文件扩展名:
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
匹配的结果集合条目;它们已经是 Matches,但是 MatchCollection 没有实现 IEnumerable<T>
因为它很旧,所以它不兼容 LINQ,除非我们做一些像 Cast 这样的事情来做到这一点。
Select
从捕获组中检索字符串值,这是.xxx
扩展,Distinct
删除重复项
你的正则表达式
至于为什么你的尝试没有奏效:
[^*]
.{3,4}
(.?)
;
这匹配
- char 是除星号以外的任何字符,
- 后跟 3 或 4 个任意字符,
- 后跟零个或任何一个字符,被捕获到一个未命名的组中,
- 后跟分号。
它可能会被调整以在某些情况下工作,但它似乎没有指定您正在寻找的字符模式
[^*]+
.
(.?)
;
这匹配
- 一个或多个字符是除星号以外的任何字符,
- 后跟任何字符,
- 后跟零个或捕获到未命名组的任何字符之一,
- 后跟分号
我怀疑您认为 ^
是一个允许匹配文字 *
的转义符 - 转义符是 \
,
当 ^
用作 [ ]
中的第一个字符时,它的意思是“除此之外的所有字符”,所以我怀疑你试图匹配一个文字星号,但你实际上最终匹配了完全相反的字符
实际上,大多数字符在字符 class 内时会失去其特殊含义,因此 [*]
将是“匹配字面星号”,就像 \*
是
您的示例字符串似乎由括号之间的可选前导部分组成,后跟竖线 |
,然后是扩展名。
如果要匹配数据的格式,可以使用同名的捕获组,Group.Captures Property.
\b[fF]iles\b[^*()]*(?:\([^()]*\))?\|\*(?<ext>\.[\w*]+)(?:[,;]\*(?<ext>\.[\w*]+))*
在部分中,模式匹配:
\b[fF]iles\b
匹配文件或文件
[^*()]*
可选择匹配除 *
(
)
之外的任何字符
(?:\([^()]*\))?
可选匹配括号之间的部分
\|\*
匹配 |*
(?<ext>\.[\w*]+)
命名组 ext,匹配 .
和 1+ 次单词 char 或 *
(?:
非捕获组
[,;]\*
匹配 ,
或 ;
后跟 *
(?<ext>\.[\w*]+)
组相同模式 ext
)*
关闭非捕获组并可选择重复它以获取所有扩展
看到一个C# regex 101 demo and a C# demo.
例如
string pattern = @"\b[fF]iles\b[^*()]*(?:\([^()]*\))?\|\*(?<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 demo。
字符串有多种变体:
"txt files `(*.txt)|*.txt|All files (*.*)|*.*`"
"Image Files`|*.jpg;*.jpeg;*.png;`"
"Excel Files `(*.xls, *.xlsx)|*.xls;*.xlsx|CSV Files (*.csv)|*.csv`"
子字符串可以以任何字符结尾(space, ',', '.', '|', ';') -
没关系。
尝试了以下选项:“[^*].{3,4}(.?);", "[^*]+.(.?);
”。
我需要一个正则表达式来得到string[] = {.jpg, .jpeg, ...}
,最好没有重复的元素。
你真的需要正则表达式吗?
首先,如果您按 |
拆分,结果中的每个奇数条目都是一个扩展名列表。然后,您可以将 再次 拆分为 ;
以获得扩展,然后您可以将其展平为单个序列和 trim 起始 [=13] 的每个元素=].最后,获取不同的集合并将其放入数组中。
这一切都可以用 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 的机会,使用捕获组更容易从字符串中提取文件扩展名:
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
匹配的结果集合条目;它们已经是 Matches,但是 MatchCollection 没有实现 IEnumerable<T>
因为它很旧,所以它不兼容 LINQ,除非我们做一些像 Cast 这样的事情来做到这一点。
Select
从捕获组中检索字符串值,这是.xxx
扩展,Distinct
删除重复项
你的正则表达式
至于为什么你的尝试没有奏效:
[^*]
.{3,4}
(.?)
;
这匹配
- char 是除星号以外的任何字符,
- 后跟 3 或 4 个任意字符,
- 后跟零个或任何一个字符,被捕获到一个未命名的组中,
- 后跟分号。
它可能会被调整以在某些情况下工作,但它似乎没有指定您正在寻找的字符模式
[^*]+
.
(.?)
;
这匹配
- 一个或多个字符是除星号以外的任何字符,
- 后跟任何字符,
- 后跟零个或捕获到未命名组的任何字符之一,
- 后跟分号
我怀疑您认为 ^
是一个允许匹配文字 *
的转义符 - 转义符是 \
,
当 ^
用作 [ ]
中的第一个字符时,它的意思是“除此之外的所有字符”,所以我怀疑你试图匹配一个文字星号,但你实际上最终匹配了完全相反的字符
实际上,大多数字符在字符 class 内时会失去其特殊含义,因此 [*]
将是“匹配字面星号”,就像 \*
是
您的示例字符串似乎由括号之间的可选前导部分组成,后跟竖线 |
,然后是扩展名。
如果要匹配数据的格式,可以使用同名的捕获组,Group.Captures Property.
\b[fF]iles\b[^*()]*(?:\([^()]*\))?\|\*(?<ext>\.[\w*]+)(?:[,;]\*(?<ext>\.[\w*]+))*
在部分中,模式匹配:
\b[fF]iles\b
匹配文件或文件[^*()]*
可选择匹配除*
(
)
之外的任何字符
(?:\([^()]*\))?
可选匹配括号之间的部分\|\*
匹配|*
(?<ext>\.[\w*]+)
命名组 ext,匹配.
和 1+ 次单词 char 或*
(?:
非捕获组[,;]\*
匹配,
或;
后跟*
(?<ext>\.[\w*]+)
组相同模式 ext
)*
关闭非捕获组并可选择重复它以获取所有扩展
看到一个C# regex 101 demo and a C# demo.
例如
string pattern = @"\b[fF]iles\b[^*()]*(?:\([^()]*\))?\|\*(?<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 demo。