Regex: Я хочу, чтобы это И было И что... в любом порядке
Я даже не уверен, что это возможно или нет, но вот что мне хотелось бы.
String: "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870"
У меня есть текстовое поле, в которое я ввожу параметры поиска, и они ограничены пробелом. Из-за этого, я хочу вернуть совпадение, строка string1 находится в строке, а строка string2 находится в строке, OR string2 - в строке, а string1 - в строке. Меня не волнует, в каком порядке находятся строки, но они ВСЕ (мне что-то больше 2) должны быть в строке.
Так, например, в предоставленной строке я бы хотел:
"FEB Low"
или
"Low FEB"
... для возврата в качестве соответствия.
Я ДЕЙСТВИТЕЛЬНО новичок в регулярном выражении, только прочитал несколько руководств по здесь, но это было давно, и мне нужно сделать это сегодня, В понедельник я начинаю новый проект, который гораздо важнее и не может быть отвлечен этой проблемой. Нужно ли вообще делать это с помощью регулярных выражений, или мне нужно перебирать каждую часть фильтра поиска и переставлять заказ? Любая помощь чрезвычайно ценится. Спасибо.
UPDATE:
Причина, по которой я не хочу перебирать петлю, и я ищу наилучшую производительность, потому что, к сожалению, dataTable, который я использую, вызывает эту функцию при каждом нажатии клавиши, и я не хочу, чтобы она увязывалась.
UPDATE:
Спасибо всем за вашу помощь, это было высоко оценено.
ОБНОВЛЕНИЕ КОДА:
В конечном счете, это то, с чем я пошел.
string sSearch = nvc["sSearch"].ToString().Replace(" ", ")(?=.*");
if (sSearch != null && sSearch != "")
{
Regex r = new Regex("^(?=.*" + sSearch + ").*$", RegexOptions.IgnoreCase);
_AdminList = _AdminList.Where<IPB>(
delegate(IPB ipb)
{
//Concatenated all elements of IPB into a string
bool returnValue = r.IsMatch(strTest); //strTest is the concatenated string
return returnValue;
}).ToList<IPB>();
}
}
В классе IPB есть X количество элементов и ни одна таблица на всем сайте, над которым я работаю, это столбцы в том же порядке. Поэтому мне нужен был поиск любого заказа, и я не хотел писать много кода для этого. Здесь были и другие хорошие идеи, но я знаю, что мой босс действительно любит Regex (проповедует их), и поэтому я подумал, что было бы лучше, если бы я пошел с этим пока. Если по какой-либо причине производительность сайта скапливается (сайт интрасети), я попробую другой способ. Спасибо всем.
Ответы
Ответ 1
Вы можете использовать (?=…)
позитивный просмотр; он утверждает, что данный шаблон можно сопоставить. Вы должны закрепить в начале строки и один за другим в любом порядке искать соответствие каждого из ваших шаблонов.
Он будет выглядеть примерно так:
^(?=.*one)(?=.*two)(?=.*three).*$
Это будет соответствовать строке, содержащей "one"
, "two"
, "three"
, в любом порядке (как показано на rubular.com).
В зависимости от контекста вы можете anchor на \A
и \Z
и использовать однострочный режим, поэтому точка соответствует всем.
Это не самое эффективное решение проблемы. Лучшим решением было бы разобрать слова на вашем входе и поставить его в эффективное представление множества и т.д.
Связанные вопросы
Более практичный пример: проверка пароля
Скажем, что мы хотим, чтобы наш пароль:
- Содержит от 8 до 15 символов
- Должна содержать заглавную букву
- Должна содержать строчную букву
- Должна содержать цифру
- Должен содержать один из специальных символов
Тогда мы можем написать такое регулярное выражение:
^(?=.{8,15}$)(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[[email protected]#$%^&*]).*$
\__________/\_________/\_________/\_________/\______________/
length upper lower digit symbol
Ответ 2
Я думаю, что наиболее целесообразным на сегодняшний день будет string.Split(' ')
условия поиска, а затем повторить результаты, подтверждающие, что sourceString.Contains(searchTerm)
var source = @"NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870".ToLowerInvariant();
var search = "FEB Low";
var terms = search.Split(' ');
bool all_match = !terms.Any(term => !(source.Contains(term.ToLowerInvariant())));
Обратите внимание, что мы используем Any()
для настройки короткого замыкания, поэтому, если первый член не подходит, мы пропускаем проверку второго, третьего и т.д.
Это не очень удобно для RegEx. Строковая манипуляция, необходимая для произвольного количества строк поиска и преобразования в шаблон, почти наверняка отрицает преимущества производительности для сопоставления шаблона с механизмом RegEx, хотя это может варьироваться в зависимости от того, с чем вы согласны.
В некоторых комментариях вы указали, что хотите избежать цикла, но RegEx не является однопроходным решением. Нетрудно создать ужасно неэффективные поиски этого цикла и символа шага по характеру, такие как печально известный катастрофический откат, где очень просто для возврата false
требуется несколько шагов.
Ответ 3
Почему бы просто не просто проверить текст, так как порядок не имеет значения?
string test = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870";
test = test.ToUpper();
bool match = ((test.IndexOf("FEB") >= 0) && (test.IndexOf("LOW") >= 0));
Вам нужно использовать регулярное выражение?
Ответ 4
var text = @"NS306Low FEBRUARY 2FEB0078/9/201013B1-9-1Low31 AUGUST 19870";
var matches = Regex.Matches(text, @"(FEB)|(Low)");
foreach (Match match in matches)
{
Console.WriteLine(match.Value);
}
Output:
Low
FEB
FEB
Low
Должен вас начать.
Ответ 5
Ответ @polygenelubricants является полным и совершенным, но у меня был случай, когда я хотел совместить дату и что-то еще, например. 10-значный номер, поэтому lookahead не соответствует, и я не могу сделать это с помощью только lookaheads, поэтому я использовал именованные группы:
(?:.*(?P<1>[0-9]{10}).*(?P<2>2[0-9]{3}-(?:0?[0-9]|1[0-2])-(?:[0-2]?[0-9]|3[0-1])).*)+
и таким образом число всегда является группой 1, а дата всегда является группой 2. Конечно, у нее есть несколько недостатков, но это было очень полезно для меня, и я просто подумал, что должен поделиться ею! (посмотрите https://www.debuggex.com/r/YULCcpn8XtysHfmE)
Ответ 6
Вам не нужно проверять каждую перестановку, просто разделите свой поиск на несколько частей "FEB" и "Low" и убедитесь, что каждая часть соответствует. Это будет намного легче, чем пытаться создать регулярное выражение, которое соответствует всему этому за один раз (что, я уверен, теоретически возможно, но, вероятно, практически не практично).
Ответ 7
Используйте string.Split(). Он вернет массив подстрок, который будет ограничен линией / char. Код будет выглядеть примерно так.
int maximumSize = 100;
string myString = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870";
string[] individualString = myString.Split(' ', maximumSize);
За дополнительной информацией
http://msdn.microsoft.com/en-us/library/system.string.split.aspx
Изменить:
Если вы действительно хотите использовать регулярные выражения, этот шаблон будет работать.
[^ ]*
И вы просто будете использовать Regex.Matches();
Код будет примерно таким:
string myString = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870";
string pattern = "[^ ]*";
Regex rgx = new Regex(pattern);
foreach(Match match in reg.Matches(s))
{
//do stuff with match.value
}