Необходимо выполнить поиск подстановочных знаков (*,? И т.д.) В строке с использованием Regex
Мне нужно выполнить подстановочный знак (*
, ?
и т.д.) в строке.
Это то, что я сделал:
string input = "Message";
string pattern = "d*";
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
if (regex.IsMatch(input))
{
MessageBox.Show("Found");
}
else
{
MessageBox.Show("Not Found");
}
С приведенным выше кодом "Найденный" блок бьет, но на самом деле он не должен!
Если мой шаблон "e *", тогда следует нажать только "Найденный".
Мое понимание или требование - поиск d * должен найти текст, содержащий "d", за которым следуют любые символы.
Должен ли я изменить свой шаблон как "d. *" и "e. *"? Есть ли какая-либо поддержка в .NET для Wild Card, которая внутренне делает это при использовании класса Regex?
Ответы
Ответ 1
Это не сложно. Из http://www.codeproject.com/KB/recipes/wildcardtoregex.aspx:
public static string WildcardToRegex(string pattern)
{
return "^" + Regex.Escape(pattern)
.Replace(@"\*", ".*")
.Replace(@"\?", ".")
+ "$";
}
Итак, что-то вроде foo*.xls?
преобразуется в ^foo.*\.xls.$
.
Ответ 2
Вы можете сделать простой шаблон без RegEx, используя функцию Visual Basic под названием LikeString.
using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;
if (Operators.LikeString("This is just a test", "*just*", CompareMethod.Text))
{
Console.WriteLine("This matched!");
}
Если вы используете CompareMethod.Text
, он будет сравнивать регистр, нечувствительный к регистру. Для сравнения с учетом регистра вы можете использовать CompareMethod.Binary
.
Дополнительная информация здесь: http://www.henrikbrinch.dk/Blog/2012/02/14/Wildcard-matching-in-C
MSDN: http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.compilerservices.operators.likestring%28v=vs.100%29.ASPX
Ответ 3
Правильная формулировка регулярного выражения выражения glob d*
равна ^d
, что означает соответствие всего, что начинается с d
.
string input = "Message";
string pattern = @"^d";
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
(В этом случае цитирование @
не обязательно, но хорошая практика, так как многие регулярные выражения используют обратные следы, которые нужно оставить в покое, а также указывает читателю, что эта строка является специальной).
Ответ 4
Windows и * nux относятся к wildcards по-разному. *
, ?
и .
обрабатываются очень сложным способом Windows, одно присутствие или позиция изменят другое значение. Хотя * nux сохраняет это просто, все, что он делает, - это просто одно совпадение шаблона. Кроме того, Windows соответствует ?
для 0 или 1 символов, Linux соответствует ей для 1 символа.
Я не нашел авторитетных документов по этому вопросу, вот только мой вывод, основанный на днях тестов на Windows 8/XP (команда командной строки, dir
) для конкретной, а метод Directory.GetFiles
использует тот же правила) и Ubuntu Server 12.04.1 (команда ls
). Я сделал десятки распространенных и необычных дел, хотя есть и много неудачных дел.
Текущий ответ Gabe, работает как * nux. Если вы также хотите использовать стиль Windows и готовы принять несовершенство, то вот оно:
/// <summary>
/// <para>Tests if a file name matches the given wildcard pattern, uses the same rule as shell commands.</para>
/// </summary>
/// <param name="fileName">The file name to test, without folder.</param>
/// <param name="pattern">A wildcard pattern which can use char * to match any amount of characters; or char ? to match one character.</param>
/// <param name="unixStyle">If true, use the *nix style wildcard rules; otherwise use windows style rules.</param>
/// <returns>true if the file name matches the pattern, false otherwise.</returns>
public static bool MatchesWildcard(this string fileName, string pattern, bool unixStyle)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
if (pattern == null)
throw new ArgumentNullException("pattern");
if (unixStyle)
return WildcardMatchesUnixStyle(pattern, fileName);
return WildcardMatchesWindowsStyle(fileName, pattern);
}
private static bool WildcardMatchesWindowsStyle(string fileName, string pattern)
{
var dotdot = pattern.IndexOf("..", StringComparison.Ordinal);
if (dotdot >= 0)
{
for (var i = dotdot; i < pattern.Length; i++)
if (pattern[i] != '.')
return false;
}
var normalized = Regex.Replace(pattern, @"\.+$", "");
var endsWithDot = normalized.Length != pattern.Length;
var endWeight = 0;
if (endsWithDot)
{
var lastNonWildcard = normalized.Length - 1;
for (; lastNonWildcard >= 0; lastNonWildcard--)
{
var c = normalized[lastNonWildcard];
if (c == '*')
endWeight += short.MaxValue;
else if (c == '?')
endWeight += 1;
else
break;
}
if (endWeight > 0)
normalized = normalized.Substring(0, lastNonWildcard + 1);
}
var endsWithWildcardDot = endWeight > 0;
var endsWithDotWildcardDot = endsWithWildcardDot && normalized.EndsWith(".");
if (endsWithDotWildcardDot)
normalized = normalized.Substring(0, normalized.Length - 1);
normalized = Regex.Replace(normalized, @"(?!^)(\.\*)+$", @".*");
var escaped = Regex.Escape(normalized);
string head, tail;
if (endsWithDotWildcardDot)
{
head = "^" + escaped;
tail = @"(\.[^.]{0," + endWeight + "})?$";
}
else if (endsWithWildcardDot)
{
head = "^" + escaped;
tail = "[^.]{0," + endWeight + "}$";
}
else
{
head = "^" + escaped;
tail = "$";
}
if (head.EndsWith(@"\.\*") && head.Length > 5)
{
head = head.Substring(0, head.Length - 4);
tail = @"(\..*)?" + tail;
}
var regex = head.Replace(@"\*", ".*").Replace(@"\?", "[^.]?") + tail;
return Regex.IsMatch(fileName, regex, RegexOptions.IgnoreCase);
}
private static bool WildcardMatchesUnixStyle(string pattern, string text)
{
var regex = "^" + Regex.Escape(pattern)
.Replace("\\*", ".*")
.Replace("\\?", ".")
+ "$";
return Regex.IsMatch(text, regex);
}
Там смешно, даже API Windows PathMatchSpec не согласен с FindFirstFile. Просто попробуйте a1*.
, FindFirstFile
говорит, что он соответствует a1
, PathMatchSpec
говорит не.
Ответ 5
d*
означает, что он должен соответствовать нулю или более символам "d
". Таким образом, любая строка является допустимым совпадением. Вместо этого попробуйте d+
!
Чтобы иметь поддержку шаблонов подстановочных знаков, я бы заменил подстановочные знаки эквивалентами RegEx. Как *
становится .*
, а ?
становится .?
. Тогда ваше выражение выше становится d.*
Ответ 6
Вам нужно преобразовать выражение подстановки в регулярное выражение. Например:
private bool WildcardMatch(String s, String wildcard, bool case_sensitive)
{
// Replace the * with an .* and the ? with a dot. Put ^ at the
// beginning and a $ at the end
String pattern = "^" + Regex.Escape(wildcard).Replace(@"\*", ".*").Replace(@"\?", ".") + "$";
// Now, run the Regex as you already know
Regex regex;
if(case_sensitive)
regex = new Regex(pattern);
else
regex = new Regex(pattern, RegexOptions.IgnoreCase);
return(regex.IsMatch(s));
}
Ответ 7
Вы должны избегать специальных символов регулярных выражений в шаблоне шаблона ввода (например, шаблон *.txt
будет эквивалентен ^.*\.txt$
)
Поэтому слэши, фигурные скобки и множество специальных символов должны быть заменены на @"\" + s
, где s
- специальный символ регулярного выражения.
Ответ 8
Весь верхний код не подходит к концу.
Это связано с тем, что при поиске zz * foo * или zz * вы не получите правильных результатов.
И если вы будете искать "abcd *" в "abcd" в TotalCommander, он найдет файл abcd, чтобы весь верхний код был неправильным.
Вот правильный код.
public string WildcardToRegex(string pattern)
{
string result= Regex.Escape(pattern).
Replace(@"\*", ".+?").
Replace(@"\?", ".");
if (result.EndsWith(".+?"))
{
result = result.Remove(result.Length - 3, 3);
result += ".*";
}
return result;
}
Ответ 9
Вы можете использовать WildcardPattern
из сборки System.Management.Automation
. См. Мой ответ здесь.
Ответ 10
Я думаю, @Dmitri имеет приятное решение на
Соответствующие строки с подстановочным знаком fooobar.com/info/95192/...
Основываясь на его решении, я создал два метода расширения. (кредит идет ему)
Может быть полезно.
public static String WildCardToRegular(this String value)
{
return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$";
}
public static bool WildCardMatch(this String value,string pattern,bool ignoreCase = true)
{
if (ignoreCase)
return Regex.IsMatch(value, WildCardToRegular(pattern), RegexOptions.IgnoreCase);
return Regex.IsMatch(value, WildCardToRegular(pattern));
}
Использование:
string pattern = "file.*";
var isMatched = "file.doc".WildCardMatch(pattern)
или
string xlsxFile = "file.xlsx"
var isMatched = xlsxFile.WildCardMatch(pattern)