Skip to content

Commit 54b7586

Browse files
yotsudaSIRMARGIN
authored andcommitted
Add ToRegex method to WildcardPattern class (PowerShell#26515)
1 parent 5329788 commit 54b7586

2 files changed

Lines changed: 106 additions & 12 deletions

File tree

src/System.Management.Automation/engine/regex.cs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,6 @@ public sealed class WildcardPattern
7373
// Default is WildcardOptions.None.
7474
internal WildcardOptions Options { get; }
7575

76-
/// <summary>
77-
/// Wildcard pattern converted to regex pattern.
78-
/// </summary>
79-
internal string PatternConvertedToRegex
80-
{
81-
get
82-
{
83-
var patternRegex = WildcardPatternToRegexParser.Parse(this);
84-
return patternRegex.ToString();
85-
}
86-
}
87-
8876
/// <summary>
8977
/// Initializes and instance of the WildcardPattern class
9078
/// for the specified wildcard pattern.
@@ -205,6 +193,35 @@ public bool IsMatch(string input)
205193
return input != null && _isMatch(input);
206194
}
207195

196+
/// <summary>
197+
/// Converts the wildcard pattern to its regular expression equivalent.
198+
/// </summary>
199+
/// <returns>
200+
/// A <see cref="Regex"/> object that represents the regular expression equivalent of the wildcard pattern.
201+
/// The regex is configured with options matching the wildcard pattern's options.
202+
/// </returns>
203+
/// <remarks>
204+
/// This method converts a wildcard pattern to a regular expression.
205+
/// The conversion follows these rules:
206+
/// <list type="bullet">
207+
/// <item><description>* (asterisk) converts to .* (matches any string)</description></item>
208+
/// <item><description>? (question mark) converts to . (matches any single character)</description></item>
209+
/// <item><description>[abc] (bracket expression) converts to [abc] (matches any character in the set)</description></item>
210+
/// <item><description>Literal characters are escaped as needed for regex</description></item>
211+
/// </list>
212+
/// </remarks>
213+
/// <example>
214+
/// <code>
215+
/// var pattern = new WildcardPattern("*.txt");
216+
/// Regex regex = pattern.ToRegex();
217+
/// // regex.ToString() returns: "\.txt$"
218+
/// </code>
219+
/// </example>
220+
public Regex ToRegex()
221+
{
222+
return WildcardPatternToRegexParser.Parse(this);
223+
}
224+
208225
/// <summary>
209226
/// Escape special chars, except for those specified in <paramref name="charsNotToEscape"/>, in a string by replacing them with their escape codes.
210227
/// </summary>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
Describe "WildcardPattern.ToRegex Tests" -Tags "CI" {
5+
It "Converts '<Pattern>' to regex pattern '<Expected>'" -TestCases @(
6+
@{ Pattern = '*.txt'; Expected = '\.txt$' }
7+
@{ Pattern = 'test?.log'; Expected = '^test.\.log$' }
8+
@{ Pattern = 'file[0-9].txt'; Expected = '^file[0-9]\.txt$' }
9+
@{ Pattern = 'test.log'; Expected = '^test\.log$' }
10+
@{ Pattern = '*test*file*.txt'; Expected = 'test.*file.*\.txt$' }
11+
@{ Pattern = 'file[0-9][a-z].txt'; Expected = '^file[0-9][a-z]\.txt$' }
12+
@{ Pattern = 'test*'; Expected = '^test' }
13+
@{ Pattern = '*test*'; Expected = 'test' }
14+
) {
15+
param($Pattern, $Expected)
16+
$wildcardPattern = [System.Management.Automation.WildcardPattern]::new($Pattern)
17+
$regex = $wildcardPattern.ToRegex()
18+
$regex | Should -BeOfType ([regex])
19+
$regex.ToString() | Should -BeExactly $Expected
20+
}
21+
22+
It "Converts '<Pattern>' with <OptionName> option" -TestCases @(
23+
@{ Pattern = 'TEST'; OptionName = 'IgnoreCase'; Option = [System.Management.Automation.WildcardOptions]::IgnoreCase; Expected = '^TEST$'; ExpectedRegexOptions = 'IgnoreCase, Singleline'; TestString = 'test'; ExpectedMatch = $true }
24+
@{ Pattern = 'test'; OptionName = 'CultureInvariant'; Option = [System.Management.Automation.WildcardOptions]::CultureInvariant; Expected = '^test$'; ExpectedRegexOptions = 'Singleline, CultureInvariant'; TestString = 'test'; ExpectedMatch = $true }
25+
@{ Pattern = 'test*'; OptionName = 'Compiled'; Option = [System.Management.Automation.WildcardOptions]::Compiled; Expected = '^test'; ExpectedRegexOptions = 'Compiled, Singleline'; TestString = 'testing'; ExpectedMatch = $true }
26+
) {
27+
param($Pattern, $OptionName, $Option, $Expected, $ExpectedRegexOptions, $TestString, $ExpectedMatch)
28+
$wildcardPattern = [System.Management.Automation.WildcardPattern]::new($Pattern, $Option)
29+
$regex = $wildcardPattern.ToRegex()
30+
$regex | Should -BeOfType ([regex])
31+
$regex.ToString() | Should -BeExactly $Expected
32+
$regex.Options.ToString() | Should -BeExactly $ExpectedRegexOptions
33+
$regex.IsMatch($TestString) | Should -Be $ExpectedMatch
34+
}
35+
36+
It "Regex from '<Pattern>' matches '<TestString>': <ShouldMatch>" -TestCases @(
37+
@{ Pattern = '*test*file*.txt'; TestString = 'mytestmyfile123.txt'; ShouldMatch = $true }
38+
@{ Pattern = 'file[0-9][a-z].txt'; TestString = 'file5a.txt'; ShouldMatch = $true }
39+
@{ Pattern = 'file[0-9][a-z].txt'; TestString = 'file55.txt'; ShouldMatch = $false }
40+
) {
41+
param($Pattern, $TestString, $ShouldMatch)
42+
$regex = [System.Management.Automation.WildcardPattern]::new($Pattern).ToRegex()
43+
$regex.IsMatch($TestString) | Should -Be $ShouldMatch
44+
}
45+
46+
Context "Edge cases" {
47+
It "Handles empty pattern" {
48+
$pattern = [System.Management.Automation.WildcardPattern]::new("")
49+
$regex = $pattern.ToRegex()
50+
$regex | Should -BeOfType ([regex])
51+
$regex.ToString() | Should -Be "^$"
52+
}
53+
54+
It "Handles pattern with only asterisk" {
55+
$pattern = [System.Management.Automation.WildcardPattern]::new("*")
56+
$regex = $pattern.ToRegex()
57+
$regex | Should -BeOfType ([regex])
58+
$regex.ToString() | Should -BeExactly ""
59+
$regex.IsMatch("anything") | Should -BeTrue
60+
$regex.IsMatch("") | Should -BeTrue
61+
}
62+
63+
It "Handles escaped '<Char>' wildcard character" -TestCases @(
64+
@{ Char = '*'; Pattern = 'file`*.txt'; Expected = '^file\*\.txt$' }
65+
@{ Char = '?'; Pattern = 'file`?.txt'; Expected = '^file\?\.txt$' }
66+
@{ Char = '['; Pattern = 'file`[.txt'; Expected = '^file\[\.txt$' }
67+
@{ Char = ']'; Pattern = 'file`].txt'; Expected = '^file]\.txt$' }
68+
) {
69+
param($Char, $Pattern, $Expected)
70+
$wildcardPattern = [System.Management.Automation.WildcardPattern]::new($Pattern)
71+
$regex = $wildcardPattern.ToRegex()
72+
$regex | Should -BeOfType ([regex])
73+
$regex.ToString() | Should -BeExactly $Expected
74+
}
75+
76+
}
77+
}

0 commit comments

Comments
 (0)