Не удается заставить работать регулярные выражения правильно с многострочным - PullRequest
15 голосов
/ 14 ноября 2008

У меня довольно большой вывод XML из приложения. Мне нужно обработать его с моей программой, а затем передать обратно в исходную программу. В этом XML есть кусочки, которые нужно заполнить заменой. Интересная часть выглядит так:

<sys:customtag sys:sid="1" sys:type="Processtart" />
    <sys:tag>value</sys:tag>
    here are some other tags
    <sys:tag>value</sys.tag>
<sys:customtag sys:sid="1" sys:type="Procesend" />

, и документ содержит несколько таких частей.

Мне нужно получить все фрагменты XML внутри этих тегов, чтобы иметь возможность вносить в них изменения. Я написал регулярное выражение, чтобы получить эти кусочки, но оно не работает:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(@"output.xml");
Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>", RegexOptions.Multiline & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant);
MatchCollection matches = regExp.Matches(xmlDoc.InnerXml);

Если я оставлю весь материал в одной строке и вызову это регулярное выражение без опции мультилинии, он найдет каждый раз Если оставить файл как есть и установить многострочный параметр, он не будет работать. В чем проблема, что я должен изменить? Или есть какой-нибудь более простой способ получить части XML между этими тегами без регулярного выражения?

Ответы [ 4 ]

45 голосов
/ 14 ноября 2008

Я считаю, что можно использовать RegexOptions.Singleline вместо RegexOptions.Multiline ( src ). разрешение (.) сопоставлять символы новой строки должно работать в вашем случае.

... режим, в котором точка также соответствует символу новой строки, называется «однострочным режимом». Это немного прискорбно, потому что этот термин легко смешать с «многострочным режимом». Многострочный режим влияет только на якоря, а однострочный режим влияет только на точку ... При использовании классов регулярных выражений .NET Framework вы активируете этот режим, указав RegexOptions.Singleline, например в строке Regex.Match (" "," regex ", RegexOptions.Singleline).

4 голосов
/ 02 декабря 2008

Если у вас все еще есть проблемы с этим, это может быть потому, что вы используете AND с RegexOptions вместо OR.

Этот код неверен и передаст ноль в качестве второго параметра конструктору:

Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>",
RegexOptions.Multiline & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant);

Этот код является правильным (если использовать несколько флагов RegexOptions):

Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>",
RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant);
4 голосов
/ 14 ноября 2008

регулярное выражение char "." никогда не соответствует новой строке, даже если установлена ​​опция MultiLine. вместо этого вы должны использовать [\s\S] или другую комбинацию с совпадениями.

Параметр MultiLine только изменяет поведение ^ (начало строки вместо начала строки) и $ (конец строки вместо конца строки)

Кстати: действительно, регулярное выражение не является правильным способом сканирования HTML ...

4 голосов
/ 14 ноября 2008

RegExp - плохой инструмент для xml ... не могли бы вы просто загрузить его в XDocument / XmlDocument и использовать xpath? Если вы уточните, какие изменения вы хотите внести, я ожидаю, что мы можем заполнить пробелы ... Пространства имен, вероятно, являются главными, чтобы сделать его сложным в этом случае, поэтому нам просто нужно использовать XmlNamespaceManager.

Вот пример, который является более сложным, чем просто регулярное выражение - однако, я ожидаю, что он намного лучше справится с нюансами xml:

    string xml = @"<foo xmlns:sys=""foobar""><bar/><bar><sys:customtag sys:sid=""1"" sys:type=""Processtart"" />
<sys:tag>value</sys:tag>
here are some other tags
<sys:tag>value</sys:tag>
<sys:customtag sys:sid=""1"" sys:type=""Procesend"" /></bar><bar/></foo>";

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml);
    XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable());
    mgr.AddNamespace("sys", "foobar");
    var matches = doc.SelectNodes("//sys:customtag[@sys:type='Processtart']", mgr);
    foreach (XmlElement start in matches)
    {
        XmlElement end = (XmlElement) start.SelectSingleNode("following-sibling::sys:customtag[@sys:type='Procesend'][1]",mgr);
        XmlNode node = start.NextSibling;
        while (node != null && node != end)
        {
            Console.WriteLine(node.OuterXml);

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