基于正则表达式创建简单的通配符/过滤器模式

Create simple wildcard / filter pattern based on regex

提问人:JohnLBevan 提问时间:7/21/2023 更新时间:7/21/2023 访问量:44

问:

上下文

在执行过滤器操作时,通常最好将过滤器推到尽可能远的上游,以获得良好的性能;例如,如果我使用 PowerShell 从目录中获取所有文件,则更可取。Get-ChildItem 'c:\temp\' -Filter '*.txt'Get-ChildItem 'c:\temp\' | Where-Object {$_.Name -like '*.txt'}

但是,在某些情况下,上游组件不会给我们提供将内容推送到上游的选项;例如,如果我们想查找任何图像文件,我们要么必须多次调用以将每种类型的不同值传递给,但会导致多次遍历目录并可能返回相同的文件(如果它们与多个过滤器匹配);或者我们必须在下游执行过滤。Get-ChildItemFilter

如果我正在搜索图像文件(对于这个特定的示例,假设是:),一种方法可能是作为过滤器发送到提供程序,因此我们在早期就排除了很多候选者,然后过滤我们感兴趣的特定扩展名下游。'*.png', '*.gif', '*.jpg', '*.jpeg''*.*g*'

问题

有没有一种已知的方法来提取表示正则表达式部分实现的“类似模式/掩码”?

例如,所以我可以实现这样的东西:

Function Get-ImageFiles {
    Param(
        [Parameter(Mandatory)]
        [string]$LiteralPath
        ,
        [Parameter()]
        [string]$Pattern = '\.(?:png|gif|jpg|jpeg)$'
    )
    $simpleMask = ConvertTo-SimpleMask -RegexPattern $Pattern
    [System.IO.Directory]::EnumerateFiles($LiteralPath, $simpleMask) |
        Select-String -Pattern $Pattern -Raw
}

# for '\.(?:png|gif|jpg|jpeg)$'      simpleMask would be '*.*g*'
# for '\.(?:jpg|jpeg)$'              simpleMask would be '*.jp*g'
# for '\.(?:png|gif|jpg|jpeg|webp)$' simpleMask would be '*.*'

注意:在这个问题中,我使用了PowerShell作为我的示例代码;但我对这个“正则表达式到简单过滤器”问题的任何解决方案感兴趣。这更像是一个好奇心问题,而不是特定于上述示例用例。

.NET 正则表达式 PowerShell 筛选

评论


答:

2赞 Mathias R. Jessen 7/21/2023 #1

不可以,您不能将任意正则表达式模式转换为通配符模式,因为通配符模式本质上是正则表达式的子集

如果性能是你最关心的问题,请枚举所有文件并根据属性进行筛选 - 这样你就根本不需要任何可变长度的匹配功能,并且比较将比任何正则表达式或通配符比较快得多:Extension

Get-ChildItem -File |Where-Object Extension -in '.png','.gif','.jpg','.jpeg'
2赞 mklement0 7/21/2023 #2

补充Mathias R. Jessen的有用答案

如果我们想找到任何图像文件,我们要么必须多次调用,将每种类型的不同值传递给 FilterGet-ChildItem

该参数允许传递多个模式,因此只需要一个 Get-ChildItem 调用。-Include

然而:

  • 与 不同,它不会在源进行筛选,并且要求 cmdlet 枚举所有项,并自行将它们与指定的模式进行匹配。-Filter-Include

  • 除非您使用 ,否则您必须结束输入路径才能按预期工作 - 有关详细信息,请参阅此答案-Recurse*-Include

  • 注意:vs支持的通配符“方言”。 (和 ) 不同:使用基础文件系统 API 的通配符模式,这些 API 的功能不如 PowerShell 的通配符,并且有许多遗留的怪癖 - 有关详细信息,请参阅此答案-Filter-Include-Exclude-Path-Filter

因此,例如:

# Note the trailing * in the (positionally implied) -Path argument,
# to make -Include work as intended.
# This isn't necessary if -Recurse is also used.
Get-ChildItem c:\temp\* -Include *.png, *.gif, *.jpg, *.jpeg

为了提高性能,您实际上可以将参数与 结合使用,这意味着您将使用 -Filter 获得快速的初步过滤,但使用误报,然后模式会消除这些误-Filter-Include-Include

# Note the use of *both* -Filter and -Include
Get-ChildItem c:\temp\* -Filter *.*g* -Include *.png, *.gif, *.jpg, *.jpeg

请注意,诸如 之类的模式不会限制部件与扩展名的匹配,并且还会匹配文件名,例如 或*.*g**g*f.g.txtf._g.txt