Регулярная битва между максимальным и минимальным мунджем - PullRequest
1 голос
/ 05 января 2010

Привет, у меня есть файл со следующими строками:

string.Format("{0},{1}", "Having \"Two\" On The Same Line".Localize(), "Is Tricky For regex".Localize());

Моя цель - получить набор совпадений с двумя строками:

  • Имея \ "два \" на одной линии
  • сложно для регулярных выражений

Мое текущее регулярное выражение выглядит так:

private Regex CSharpShortRegex = new Regex("\"(?<constant>[^\"]+?)\".Localize\\(\\)");

Моя проблема с кавычками в первой строке, в которых я остановился, и получил:

  • На той же линии
  • слишком сложно для этого стиля

однако попытка игнорировать экранированные кавычки не работает, потому что это делает Regex жадным, и я получаю

  • Наличие \ "Два \" на одной строке ".Localize ()," Хитрый для регулярных выражений "

Кажется, мы застряли между максимальным и минимальным мунджем. Есть ли надежда? У меня есть несколько планов резервного копирования. Можете ли вы Regex задом наперед? это облегчит задачу, потому что я могу начать с "() ezilacoL."

EDIT: Чтобы уточнить. Это мой крайний случай. Большую часть времени строка сидит одна:

var myString = "Hot Patootie".Localize()

Ответы [ 5 ]

1 голос
/ 05 января 2010

Вот регулярное выражение, которое вам нужно:

@"""(?<constant>(\\.|[^""])*)""\.Localize\(\)"

Тестовая программа:

с использованием системы; использование System.Text.RegularExpressions; используя System.IO;

class Program
{
    static void Main()
    {
        Regex CSharpShortRegex =
            new Regex(@"""(?<constant>(\\.|[^""])*)""\.Localize\(\)");

        foreach (string line in File.ReadAllLines("input.txt"))
            foreach (Match match in CSharpShortRegex.Matches(line))
                Console.WriteLine(match.Groups["constant"].Value);
    }
}

Выход:

Having \"Two\" On The Same Line
Is Tricky For regex
Hot Patootie

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

1 голос
/ 05 января 2010

Это работает для меня:

\"((?:[^\\"]|(?:\\\"))*)\"\.Localize\(\)

Проверено на http://www.regexplanet.com/simple/index.html против ряда строк с различными экранированными кавычками.

Похоже, большинство из нас, кто ответил на это, имели ту же грубую идею, поэтому позвольте мне объяснить подход (комментарии после # с):

\"             # We're looking for a string delimited by quotation marks
(              # Capture the contents of the quotation marks
  (?:          #   Start a non-capturing group
    [^\\"]     #     Either read a character that isn't a quote or a slash
    |(?:\\\")  #     Or read in a slash followed by a quote.
  )*           #   Keep reading
)              # End the capturing group
\"             # The string literal ends in a quotation mark
\.Localize\(\) # and ends with the literal '.Localize()', escaping ., ( and )

Для C # вам нужно дважды избегать косых черт (грязно):

\"((?:[^\\\\\"]|(?:\\\\\"))*)\"\\.Localize\\(\\)

Марк правильно указывает, что этот символ не соответствует экранированным символам, кроме кавычек. Итак, вот лучшая версия:

\"((?:[^\\"]|(?:\\")|(?:\\.))*)\"\.Localize\(\)

И его сокращенный эквивалент:

\"((?:[^\\\\\"]|(?:\\\\\")|(?:\\\\.))*)\"\\.Localize\\(\\)

Работает так же, за исключением особого случая, когда, если он встречает косую черту, но не может соответствовать \", он просто использует косую черту и следующий символ и движется дальше.


Думая об этом, лучше всего потреблять два символа в каждом слэше, что фактически является ответом Марка, поэтому я не буду повторять его.

1 голос
/ 05 января 2010

Обновление:

Мой исходный ответ (ниже горизонтального правила) содержит ошибку: сопоставители регулярных выражений пытаются найти альтернативы в порядке слева направо. Наличие [^"] в качестве первой альтернативы позволяет ему использовать обратную косую черту, но затем следующий символ, который должен быть сопоставлен, является кавычкой, которая препятствует продолжению совпадения.

Примечание о несовместимости: Учитывая приведенный ниже шаблон, perl возвращается к другой альтернативе (экранированная кавычка) и успешно находит совпадение для случая Having \"Two\" On The Same Line.

Исправление состоит в том, чтобы сначала попытаться использовать экранированную цитату, а затем не-кавычку:

var CSharpShortRegex =
  new Regex("\"(?<constant>(\\\\\"|[^\"])*)\"\\.Localize\\(\\)");

или, если вы предпочитаете строковую форму:

var CSharpShortRegex =
  new Regex(@"""(?<constant>(\\""|[^""])*)""\.Localize\(\)");

Разрешить побег:

private Regex CSharpShortRegex =
  new Regex("\"(?<constant>([^\"]|\\\\\")*)\"\\.Localize\\(\\)");

Применяя один уровень экранирования для облегчения чтения шаблона, мы получаем

"(?<constant>([^"]|\\")*)"\.Localize\(\)

То есть строка начинается и заканчивается " символами, а все, что находится между ними, - это не кавычка или экранированная кавычка.

0 голосов
/ 05 января 2010
new Regex(@"((([^@]|^|\n)""(?<constant>((\\.)|[^""])*)"")|(@""(?<constant>(""""|[^""])*)""))\s*\.\s*Localize\s*\(\s*\)", RegexOptions.Compiled);

заботится как о простых, так и о @ "" строках. Он также учитывает escape-последовательности.

0 голосов
/ 05 января 2010

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

var cr = new CSharpCodeProvider().CompileAssemblyFromSource(
    new CompilerParameters { GenerateInMemory = true }, 
    "class x { public static string e() { return " + input + "}}");

var result = cr.CompiledAssembly.GetType("x")
    .GetMethod("e").Invoke(null, null) as string;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...