#regex
#регулярное выражение
Вопрос:
Я пытаюсь добавить поиск по совпадению всего слова в мое небольшое приложение. Я хочу, чтобы оно выполняло то же самое, что и Visual Studio. Так, например, приведенный ниже код должен работать нормально:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
String input = "[ abc() *abc ]";
Match(input, "abc", 2);
Match(input, "abc()", 1);
Match(input, "*abc", 1);
Match(input, "*abc ", 1);
}
private void Match(String input, String pattern, int expected)
{
String escapedPattern = Regex.Escape(pattern);
MatchCollection mc = Regex.Matches(input, @"b" escapedPattern @"b", RegexOptions.IgnoreCase);
if (mc.Count != expected)
{
throw new Exception("match whole word isn't working");
}
}
}
Поиск по «abc» работает нормально, но другие шаблоны возвращают 0 результатов.
Я думаю, что b не подходит, но я не уверен, что использовать.
Будем признательны за любую помощь. Спасибо
Ответ №1:
b
Метасимвол совпадает со словом-границей между буквенно-цифровым и не буквенно-цифровым символом. Строки, которые заканчиваются не буквенно-цифровыми символами, в конечном итоге не совпадают, поскольку b
работает должным образом.
Чтобы выполнить правильное сопоставление всего слова, поддерживающее оба типа данных, вам необходимо:
- используйте
b
перед или после любого буквенно — цифрового символа - используйте
B
(заглавнуюB
) перед или после любого не буквенно-цифрового символа - не использовать
B
, если первый или последний символ шаблона намеренно не является буквенно-цифровым символом, например, в вашем последнем примере с завершающим пробелом
На основе этих пунктов вам потребуется дополнительная логика для проверки входящего поискового запроса, чтобы сформировать его в соответствующий шаблон. B
работает противоположным образом b
. Если вы не используете B
, то у вас могут неправильно получиться частичные совпадения. Например, слово foo*abc
было бы неправильно сопоставлено с шаблоном @"*abcb"
.
Чтобы продемонстрировать:
string input = "[ abc() *abc foo*abc ]";
string[] patterns =
{
@"babcb", // 3
@"babc()B", // 1
@"B*abcb", // 1, B prefix ensures whole word match, "foo*abc" not matched
@"*abcb", // 2, no B prefix so it matches "foo*abc"
@"B*abc " // 1
};
foreach (var pattern in patterns)
{
Console.WriteLine("Pattern: " pattern);
var matches = Regex.Matches(input, pattern);
Console.WriteLine("Matches found: " matches.Count);
foreach (Match match in matches)
{
Console.WriteLine(" " match.Value);
}
Console.WriteLine();
}
Ответ №2:
Я думаю, это то, что вы ищете:
@"(?<!w)" escapedPattern @"(?!w)"
b
определяется в терминах наличия или отсутствия символов «word» как до, так и после текущей позиции. Вас волнует только то, что находится перед первым символом и что находится после последнего.
Ответ №3:
b
Это утверждение нулевой ширины, которое соответствует символу word и символу, не являющемуся словом.
Буквы, цифры и подчеркивания являются символами word. *
, ПРОБЕЛ и скобки в скобках не являются символами word. поэтому, когда вы используете b*abcb
в качестве шаблона, он не соответствует вашему вводу, потому что * не является словом. Аналогично для вашего шаблона, включающего скобки.
Чтобы решить эту проблему, вам нужно будет устранить b
в случаях, когда ваш шаблон ввода (неэкранированный) начинается или заканчивается символами, отличными от word.
public void Run()
{
String input = "[ abc() *abc ]";
Match(input, @"babcb", 2);
Match(input, @"babc()", 1);
Match(input, @"*abcb", 1);
Match(input, @"*abcb ", 1);
}
private void Match(String input, String pattern, int expected)
{
MatchCollection mc = Regex.Matches(input, pattern, RegexOptions.IgnoreCase);
Console.WriteLine((mc.Count == expected)? "PASS ({0}=={1})" : "FAIL ({0}!={1})",
mc.Count, expected);
}