我有一个通配符模式,可能是“* .txt”或“POS ??。dat”。
我还有内存中需要与该模式进行比较的文件名列表。
我将如何做到这一点,请记住,我需要与IO.DirectoryInfo.GetFiles(模式)使用完全相同的语义。
编辑:盲目地将其翻译成正则表达式将无效。
答案 0 :(得分:43)
我在代码中有一个完整的答案,95%像FindFiles(string)
。
此函数的MSDN文档的第二个注释中有5%不存在短名称/长名称行为。
如果您仍然希望获得该行为,则必须完成对输入数组中每个字符串的短名称的计算,然后将长名称添加到匹配集合中或短名称与模式匹配。
以下是代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace FindFilesRegEx
{
class Program
{
static void Main(string[] args)
{
string[] names = { "hello.t", "HelLo.tx", "HeLLo.txt", "HeLLo.txtsjfhs", "HeLLo.tx.sdj", "hAlLo20984.txt" };
string[] matches;
matches = FindFilesEmulator("hello.tx", names);
matches = FindFilesEmulator("H*o*.???", names);
matches = FindFilesEmulator("hello.txt", names);
matches = FindFilesEmulator("lskfjd30", names);
}
public string[] FindFilesEmulator(string pattern, string[] names)
{
List<string> matches = new List<string>();
Regex regex = FindFilesPatternToRegex.Convert(pattern);
foreach (string s in names)
{
if (regex.IsMatch(s))
{
matches.Add(s);
}
}
return matches.ToArray();
}
internal static class FindFilesPatternToRegex
{
private static Regex HasQuestionMarkRegEx = new Regex(@"\?", RegexOptions.Compiled);
private static Regex IllegalCharactersRegex = new Regex("[" + @"\/:<>|" + "\"]", RegexOptions.Compiled);
private static Regex CatchExtentionRegex = new Regex(@"^\s*.+\.([^\.]+)\s*$", RegexOptions.Compiled);
private static string NonDotCharacters = @"[^.]*";
public static Regex Convert(string pattern)
{
if (pattern == null)
{
throw new ArgumentNullException();
}
pattern = pattern.Trim();
if (pattern.Length == 0)
{
throw new ArgumentException("Pattern is empty.");
}
if(IllegalCharactersRegex.IsMatch(pattern))
{
throw new ArgumentException("Pattern contains illegal characters.");
}
bool hasExtension = CatchExtentionRegex.IsMatch(pattern);
bool matchExact = false;
if (HasQuestionMarkRegEx.IsMatch(pattern))
{
matchExact = true;
}
else if(hasExtension)
{
matchExact = CatchExtentionRegex.Match(pattern).Groups[1].Length != 3;
}
string regexString = Regex.Escape(pattern);
regexString = "^" + Regex.Replace(regexString, @"\\\*", ".*");
regexString = Regex.Replace(regexString, @"\\\?", ".");
if(!matchExact && hasExtension)
{
regexString += NonDotCharacters;
}
regexString += "$";
Regex regex = new Regex(regexString, RegexOptions.Compiled | RegexOptions.IgnoreCase);
return regex;
}
}
}
}
答案 1 :(得分:11)
你可以这样做。你不需要正则表达式。
using Microsoft.VisualBasic.CompilerServices;
if (Operators.LikeString("pos123.txt", "pos?23.*", CompareMethod.Text))
{
Console.WriteLine("Filename matches pattern");
}
或者,在VB.Net中,
If "pos123.txt" Like "pos?23.*" Then
Console.WriteLine("Filename matches pattern")
End If
在c#中你可以用扩展方法模拟这个。它不会像VB Like那样,但它会......非常酷。
答案 2 :(得分:2)
您可以将通配符转换为正则表达式:
*.txt -> ^.+\.txt$
POS??.dat _> ^POS..\.dat$
使用Regex.Escape
方法将非野花字符转义为模式的文字字符串(例如,将".txt"
转换为"\.txt"
)。
通配符*
转换为.+
,?
转换为.
将^放在模式的开头以匹配字符串的开头,将$放在结尾以匹配字符串的结尾。
现在,您可以使用Regex.IsMatch
方法检查文件名是否与模式匹配。
答案 3 :(得分:2)
某种正则表达式/ glob是可行的方法,但有一些细微之处;您的问题表明您希望IO.DirectoryInfo.GetFiles
具有相同的语义。这可能是一个挑战,因为涉及8.3与长文件名等的特殊情况。整个故事发生在MSDN。
如果您不需要精确的行为匹配,那么有几个好的SO问题:
答案 4 :(得分:2)
只需调用Windows API函数PathMatchSpecExW()。
[Flags]
public enum MatchPatternFlags : uint
{
Normal = 0x00000000, // PMSF_NORMAL
Multiple = 0x00000001, // PMSF_MULTIPLE
DontStripSpaces = 0x00010000 // PMSF_DONT_STRIP_SPACES
}
class FileName
{
[DllImport("Shlwapi.dll", SetLastError = false)]
static extern int PathMatchSpecExW([MarshalAs(UnmanagedType.LPWStr)] string file,
[MarshalAs(UnmanagedType.LPWStr)] string spec,
MatchPatternFlags flags);
/*******************************************************************************
* Function: MatchPattern
*
* Description: Matches a file name against one or more file name patterns.
*
* Arguments: file - File name to check
* spec - Name pattern(s) to search foe
* flags - Flags to modify search condition (MatchPatternFlags)
*
* Return value: Returns true if name matches the pattern.
*******************************************************************************/
public static bool MatchPattern(string file, string spec, MatchPatternFlags flags)
{
if (String.IsNullOrEmpty(file))
return false;
if (String.IsNullOrEmpty(spec))
return true;
int result = PathMatchSpecExW(file, spec, flags);
return (result == 0);
}
}
答案 5 :(得分:1)
对于现在遇到这个问题的人,多年后,我在MSDN社交网站上发现GetFiles()方法会接受*和? searchPattern参数中的通配符。 (至少在.Net 3.5,4.0和4.5中)
Directory.GetFiles(string path, string searchPattern)
答案 6 :(得分:0)
Plz尝试以下代码。
static void Main(string[] args)
{
string _wildCardPattern = "*.txt";
List<string> _fileNames = new List<string>();
_fileNames.Add("text_file.txt");
_fileNames.Add("csv_file.csv");
Console.WriteLine("\nFilenames that matches [{0}] pattern are : ", _wildCardPattern);
foreach (string _fileName in _fileNames)
{
CustomWildCardPattern _patetrn = new CustomWildCardPattern(_wildCardPattern);
if (_patetrn.IsMatch(_fileName))
{
Console.WriteLine("{0}", _fileName);
}
}
}
public class CustomWildCardPattern : Regex
{
public CustomWildCardPattern(string wildCardPattern)
: base(WildcardPatternToRegex(wildCardPattern))
{
}
public CustomWildCardPattern(string wildcardPattern, RegexOptions regexOptions)
: base(WildcardPatternToRegex(wildcardPattern), regexOptions)
{
}
private static string WildcardPatternToRegex(string wildcardPattern)
{
string patternWithWildcards = "^" + Regex.Escape(wildcardPattern).Replace("\\*", ".*");
patternWithWildcards = patternWithWildcards.Replace("\\?", ".") + "$";
return patternWithWildcards;
}
}
答案 7 :(得分:-2)
只需使用Regex类。使用您正在考虑的通配符模式对其进行初始化,然后使用.IsMatch(filename)方法检查每个文件名以查看它是否匹配。
答案 8 :(得分:-2)
使用RegexOptions.IgnoreCase将修复它。
public class WildcardPattern : Regex {
public WildcardPattern(string wildCardPattern)
: base(ConvertPatternToRegex(wildCardPattern), RegexOptions.IgnoreCase) {
}
public WildcardPattern(string wildcardPattern, RegexOptions regexOptions)
: base(ConvertPatternToRegex(wildcardPattern), regexOptions) {
}
private static string ConvertPatternToRegex(string wildcardPattern) {
string patternWithWildcards = Regex.Escape(wildcardPattern).Replace("\\*", ".*");
patternWithWildcards = string.Concat("^", patternWithWildcards.Replace("\\?", "."), "$");
return patternWithWildcards;
}
}