Запрос Regex для SQL дает пустой MatchCollection - PullRequest
2 голосов
/ 15 ноября 2008

Я стараюсь быть кратким и лаконичным. Я должен написать программу, которая принимает запросы в форме SQL и ищет XML. Прямо сейчас я пытаюсь разобрать строку на логические части, чтобы я мог работать с ними. У меня есть строка в качестве ввода и я хочу получить MatchCollection в качестве вывода.

Обратите внимание, что приведенная ниже тестовая строка имеет специальный формат, который я навязываю пользователю, чтобы все было просто. Разрешен только один оператор на строку, а вложенные запросы исключены-

string testString = "выбрать яблоки \ n из dblp \ r, где мы съели \ n группу по всем из них \ r НЕ ИМЕЯ СТРАДА \ n";

Я использую Regex со следующим шаблоном:

Regex reg = new Regex(@"(?<select> \A\bselect\b .)" +  
                      @"(?<from> ^\bfrom\b .)" +
                      @"(?<where> ^\bwhere\b .)" +
                      @"(?<groupBy> ^\bgroup by\b .)" +
                      @"(?<having> ^\bhaving\b .)"
                      , RegexOptions.IgnoreCase | RegexOptions.Multiline
                      );

Насколько я знаю, это должно дать мне совпадения для каждой группы с тестовой строкой. Я бы искал точное совпадение слова «select» в начале каждой строки, за которым следовали бы любые символы, кроме символов новой строки.

Теперь я создаю коллекцию:

MatchCollection matches = reg.Matches(testString);

Чтобы убедиться, что это сработало, я использовал foreach и напечатал спички, такие как:

foreach(Match match in matches)
{
    Console.WriteLine("Select: {0}", match.Groups["select"]);
   //and so on
}

Проблема в том, что коллекция всегда пуста. Где-то в Regex должен быть какой-то недостаток, но я слишком неопытен, чтобы его найти. Не могли бы вы помочь мне? Большое спасибо!


Я пытался использовать. * Вместо просто. пока мне не сказали это. будет даже mathc несколько символов. Я не сомневаюсь, что это может быть проблемой, но даже при ее замене я не получаю результата.

Я не понимаю, почему так сложно сопоставить строку, начинающуюся с определенного слова, с добавлением любых символов до тех пор, пока регулярное выражение не найдет новую строку. Сдается мне, что это должно быть относительно легкой задачей.

Ответы [ 4 ]

3 голосов
/ 16 ноября 2008

Я думаю, вам нужно явно сопоставить терминаторы строки, а также лучше обрабатывать пробелы, как предлагали другие. Предполагая, что пользователь может выбирать между \ r и \ n, попробуйте

@"(?<select>\Aselect .+)[\n\r]" +
@"(?<from>\s*from .+)[\n\r]" +
@"(?<where>\s*where .+)[\n\r]" +
@"(?<groupBy>\s*group by .+)[\n\r]" +
@"(?<having>\s*having .+)[\n\r]"

Пока вы используете регулярные выражения, вы, вероятно, захотите сделать немного лучше:

@"\Aselect (?<select>.+)[\n\r]" +
@"\s*from (?<from>.+)[\n\r]" +
@"\s*where (?<where>.+)[\n\r]" +
@"\s*group by (?<groupBy>.+)[\n\r]" +
@"\s*having (?<having>.+)[\n\r]"

Моя самая большая проблема с регулярными выражениями для такого рода использования заключается в том, что единственное сообщение об ошибке, которое вы можете дать, - это что-то не так. Вы не можете предоставить пользователю дополнительную информацию о том, что он сделал неправильно.

0 голосов
/ 16 ноября 2008

Я не пытался создать для вас работающее регулярное выражение, но вижу несколько проблем. Другие указали на первые два вопроса, но не на третий.

  1. Нельзя использовать одну точку для сопоставления с переменными частями, такими как «яблоки». Попробуйте \ w + или \ S +
  2. В вашей строке есть разрывы строк. Вам необходимо сопоставить их с [\ r \ n] + или \ s +
  3. Механизм регулярных выражений .NET обрабатывает \ n как разрыв строки, но НЕ \ r или \ r \ n. Таким образом, ^ будет соответствовать после \ n, но НЕ после \ r. Если вы выполните шаг 2, якоря вам все равно не понадобятся, поэтому удалите их.
0 голосов
/ 16 ноября 2008

Как вы сказали, достаточно просто сопоставить ключевое слово (а), а затем использовать (. +) Для сопоставления с остальной частью строки. Но вы должны соответствовать всем промежуточным персонажам, а вы этого не делаете. (Якорь ^ соответствует позиции после разделителя строк, а не самого разделителя.) Вы можете использовать \ s +, чтобы использовать разделитель строк, а также любой начальный пробел в следующей строке.

@"select\s+(?<select>.+)\s+" +
@"from\s+(?<from>.+)\s+" +
@"where\s+(?<where>.+)\s+" +
@"group by\s+(?<groupBy>.+)\s+" +
@"having\s+(?<having>.+)";

Я также переставил вещи так, чтобы ключевые слова SQL не фиксировались; это кажется излишним, так как вы используете именованные группы.

0 голосов
/ 16 ноября 2008

Может быть проблема с соответствием новой строки: LF (стандарт Unix), CR (MacOS) или CR LF (Windows)? Если вы не знаете, возможно, вам следует сопоставить его с: [\n\r]+

edit : Вы включили в тестовую строку некоторые пробелы, окружающие символы новой строки, которые вы не учитываете в своем rexex.

(?<from>^\s*from\b.*[\n\r]+$)
...