【问题标题】:How do I replace matched groups in a regex?如何替换正则表达式中的匹配组?
【发布时间】:2019-02-01 16:30:27
【问题描述】:

给定一些输入数据:

<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>

我想用JonSomeSaltedPassword替换用户区域中没有C:权限的第一个用户(在本例中为MrFlibble)和SomeSaltedPassword使用.net框架正则表达式给出以下结果:

<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>

...但我正在努力寻找如何在保留其他文本的同时替换这三个组。 The docs 似乎都建议用特定的新文本替换原始文本的修改,而不是多个特定命名的组。

有没有标准的方法可以做到这一点,还是我找错了树?

【问题讨论】:

  • 用正则解析HTML是邪恶的,相当于杀了一只小猫。
  • 谢谢。很有帮助。那你会怎么解决呢?
  • 是什么阻止你做一个简单的替换?即找到Name="MrFlibble" 并替换为Name="Jon"
  • 不保证最初是MrFlibble,我不想匹配条目中的C:。我应该在问题中说明这一点。现在会这样做。

标签: .net regex c++-cli


【解决方案1】:

在任何情况下都不要尝试使用正则表达式解析 XML,除非您希望调用 rite 666Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn。

使用 XML 解析库,请参阅 this page 了解一些方法。

【讨论】:

  • 第二个答案在第一个链接中更详细地描述了我认为的用例。这是在一个非常封闭的环境中的一些格式良好的 XML,而不是从随机网站中抓取一些可能格式很糟糕的 XHTML。
  • 听从了您的建议,在大门尚未完全成型之前就勉强关闭了大门。在此过程中理智值 -4 并在 Arkham Asylum 中为我的麻烦醒来... ... Dobbs 博士让我度过了难关!
【解决方案2】:

正则表达式很难做到这一点,因为您需要按条件替换。

在您写的评论中,它是格式良好的 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");

【讨论】:

  • 很遗憾,我的平台仅限于.net 2.0,所以我无法使用Linq
【解决方案3】:

带有正则表达式的选项。表达式本身看起来晦涩难懂,因此难以维护。因此,最好使用带有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);

【讨论】:

    猜你喜欢
    • 2012-05-16
    • 1970-01-01
    • 2012-11-23
    • 2022-08-10
    • 2016-02-11
    • 1970-01-01
    • 2013-12-06
    • 2021-04-10
    • 1970-01-01
    相关资源
    最近更新 更多