Как заменить соответствующие группы в регулярном выражении? - PullRequest
0 голосов
/ 01 февраля 2019

Учитывая некоторые входные данные:

<somexml>
    <User Name="MrFlibble">
        <Option Name="Pass">SomeSaltedPassword</Option>
        <Option Name="Salt">Salt</Option>
        <tag1></tag1>
        <Permissions>
            <Permission Dir="E:"></Permission>
        </Permissions>
    </User>
    <User Name="MrFlobble">
        <Option Name="Pass">SomeOtherSaltedPassword</Option>
        <Option Name="Salt">Salt</Option>
        <tag1></tag1>
        <Permissions>
            <Permission Dir="C:"></Permission>
        </Permissions>
    </User>
</somexml>

Я хотел бы заменить первого пользователя, у которого нет разрешения C: в пользовательской области (в данном случае MrFlibble), на Jon и SomeSaltedPassword с MyNewSaltedPassword с использованием регулярного выражения .net framework для получения следующего результата:

<somexml>
    <User Name="Jon">
        <Option Name="Pass">MyNewSaltedPassword</Option>
        <Option Name="Salt">Salt</Option>
        <tag1></tag1>
        <Permissions>
            <Permission Dir="E:"></Permission>
        </Permissions>
    </User>
    <User Name="MrFlobble">
        <Option Name="Pass">SomeOtherSaltedPassword</Option>
        <Option Name="Salt">Salt</Option>
        <tag1></tag1>
        <Permissions>
            <Permission Dir="C:"></Permission>
        </Permissions>
    </User>
</somexml>

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

<User Name="(.*)">.*<Option Name="Pass">(.*)<\/Option>.*<Option Name="Salt">(.*)<\/Option>.*<\/User>

... но я изо всех сил пытаюсь понять, как бы я заменил три группы при сохранении другого текста. Все документы , по-видимому, предполагают замену модификаций исходного текста, а не нескольких специально названных групп конкретным новым текстом.

Есть ли стандартный способ сделать это, или я лаю неправильнодерево

Ответы [ 3 ]

0 голосов
/ 02 февраля 2019

Это довольно сложно сделать с регулярными выражениями, потому что вам нужна замена условием.

В комментарии вы написали, что это правильно сформированный xml.Поэтому я осмелюсь предложить решение с использованием синтаксического анализатора xml.

Добавить ссылку на библиотеку System.Xml.Linq в проект.
Открыть следующие пространства имен

using namespace System;
using namespace System::IO;
using namespace System::Xml::Linq;

Кодочень просто и лаконично

//auto xml = XElement::Parse(input); // input - string containing your xml
auto xml = XElement::Load(L"test.xml");

for each (auto user in xml->Elements(L"User"))
{
    if (user->Element(L"Permissions")->Element(L"Permission")->Attribute(L"Dir")->Value != L"C:")
    {
        user->Attribute(L"Name")->Value = L"Jon";

        for each(auto option in user->Elements(L"Option"))
        {
            if (option->Attribute(L"Name")->Value == L"Pass")
            {
                option->Value = L"MyNewSaltedPassword";
            }
        }
    }
}

Console::WriteLine(xml);
//xml->Save(L"result.xml");
0 голосов
/ 02 февраля 2019

Вариант с регулярными выражениями.Само выражение выглядит неясным, в результате его трудно поддерживать.Поэтому лучше использовать метод с анализатором xml.

using namespace System;
using namespace System::IO;
using namespace System::Text::RegularExpressions;

Метод MatchEvaluator:

String^ Evaluate(Match^ m)
{
    if (m->Groups[L"dir"]->Value != L"C:")
        return L"Jon" + m->Groups[L"mid1"] + L"MyNewSaltedPassword" + m->Groups[L"mid2"] + m->Groups[L"dir"];
    else
        return m->Groups[L"name"]->Value + m->Groups[L"mid1"] + m->Groups[L"pass"] + m->Groups[L"mid2"] + m->Groups[L"dir"];
}

Код:

auto input = File::ReadAllText(L"test.xml");

auto pattern = gcnew String(R"(
(?<= <User \s Name = " )
(?'name' .+? )
(?= "> )

(?'mid1' .+? )

(?<= <Option \s Name = "Pass"> )
(?'pass' .+? )
(?= </Option> )

(?'mid2' .+? )

(?<= <Permission \s Dir = " )
(?'dir' .+? )
(?= "> )
)");

auto options = RegexOptions::IgnorePatternWhitespace | RegexOptions::Singleline;

auto evaluator = gcnew MatchEvaluator(Evaluate);
auto result = Regex::Replace(input, pattern, evaluator, options);

Console::WriteLine(result);
0 голосов
/ 01 февраля 2019

Ни при каких обстоятельствах не пытайтесь анализировать XML с помощью регулярного выражения, если вы не хотите вызывать обряд 6 6 6 Ph'nglui mglw 'nafh Cthulhu R'lyeh wgah'nagl fhtagn.

Используйте библиотеку синтаксического анализа XML, см. эту страницу , чтобы узнать, как это сделать.

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