Подтвердить что ты не робот

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 (проповедует их), и поэтому я подумал, что было бы лучше, если бы я пошел с этим пока. Если по какой-либо причине производительность сайта скапливается (сайт интрасети), я попробую другой способ. Спасибо всем.

4b9b3361

Ответ 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
}