【问题标题】:Reg Ex negation not working in XML string正则表达式否定在 XML 字符串中不起作用
【发布时间】:2011-05-01 22:49:55
【问题描述】:

我正在尝试对 .Net 中的正则表达式应用否定。这是行不通的。当字符串具有有效的姓氏时,reg ex 不应匹配。对于无效的姓氏,它应该匹配。有效名称仅允许字符、空格、单引号和 1-40 之间的长度。有人建议解析 XML,我不想这样做。我知道还有另一种方法可以通过删除 reg ex 中的否定并反转代码中的匹配条件来做到这一点。但我也不想这样。为此,我需要纯 reg ex 解决方案。

这是我的代码。这确实与有效的姓氏相匹配。但我不想匹配。

string toBevalidated = @"<FirstName>SomeName</FirstName><LastName>Some</LastName><Address1>Addre1</Address1>";
        var regex = new Regex(@"<LastName>([^a-zA-Z'\s])|(.{41,})</LastName>");
        var match = regex.Match(toBevalidated);

        // Check to see if a match was found
        if (match.Success)
        {
            Console.WriteLine("Success");
        }
        else
        {
            Console.WriteLine("Failed");
        }

编辑: 这里有一些混乱,让我举一些我打算做的例子。当姓氏有效时,reg ex 不应匹配。例如下面的示例不应与 reg ex 匹配

案例一

<FirstName>SomeName</FirstName><LastName>Brian</LastName><Address1>Addre1</Address1>

案例 2

<FirstName>SomeName</FirstName><LastName>O'neil</LastName><Address1>Addre1</Address1>

案例 3

<FirstName>SomeName</FirstName><LastName>Peter John</LastName><Address1>Addre1</Address1>

当姓氏无效时,reg ex 应该匹配

案例4

<FirstName>SomeName</FirstName><LastName>Brian123</LastName><Address1>Addre1</Address1>

案例5

<FirstName>SomeName</FirstName><LastName>#Brian</LastName><Address1>Addre1</Address1>

案例6

<FirstName>SomeName</FirstName><LastName>BrianBrianBrianBrianBrianBrianBrianBrianBrianBrian</LastName><Address1>Addre1</Address1>

如果您需要更多信息,请告诉我

【问题讨论】:

  • 为什么你不想解析 XML?在 XML 上使用正则表达式是个坏主意——它非常脆弱。
  • 你为什么不继续你昨天问的问题,开始一个新的,stackoverflow.com/questions/4037631/reg-ex-negation/…
  • 请听 Skeet 男子的声音并停止。您认为这在生产中“完美运行”,但是一旦您遇到任何异常,例如已转义的字符 (O&amp;#39;Reilly),或 XML 格式中任何微小的完全有效的更改,例如新属性或者只是标记中的一些空格,您的正则表达式将很难失败。这是超级脆的。 .NET 具有良好的 XML 支持,这使得从此类格式中正确提取简单的 XML 数据变得异常容易。使用它,您的代码将更加健壮并且更具可读性。
  • 我敢打赌,在这种情况下,“这在生产中完美运行”意味着“如果它在 1% 的时间内失败,我们无法知道这一点。”
  • “但就这个问题而言,我们不想解析 XML。”然后不要使用 XML。使用您完全理解的更简单的格式。人们使用 XML 而不对其进行解析的唯一情况是 a) 当他们不理解 XML 或 b) 当他们不应该使用 XML。

标签: .net xml regex-negation


【解决方案1】:

如果你给出一个不符合你预期的例子会很有帮助,但我怀疑这是因为你只匹配一个无效字符,如果它是一个 单个无效字符,例如

<LastName>5</LastName>

会匹配(我相信;我没有检查过),但这不会:

<LastName>55</LastName>

认为你可以这样做:

<LastName>(.*[^a-zA-Z'\s].*)|(.{41,})</LastName>

确保其中有至少一个无效字符(或有 41 个或更多字符)。但这里可能存在不合适的极端情况。

编辑:知道了。交替运算符将其前面的 everything 作为选项,而不仅仅是前面的组。最终的正则表达式为:

<LastName>((.*[^a-zA-Z'\s].*)|(.{41,}))</LastName>

下面是一些示例代码:

using System;
using System.Text.RegularExpressions;

class Test
{
    static void Main()
    {
        string pattern = @"<LastName>((.*[^a-zA-Z'\s].*)|(.{41,}))</LastName>";
        Regex regex = new Regex(pattern);

        string[] samples = {
            "<FirstName>SomeName</FirstName><LastName>Brian</LastName><Address1>Addre1</Address1>",
            "<FirstName>SomeName</FirstName><LastName>O'neil</LastName><Address1>Addre1</Address1>",
            "<FirstName>SomeName</FirstName><LastName>Peter John</LastName><Address1>Addre1</Address1>",
            "<FirstName>SomeName</FirstName><LastName>Brian123</LastName><Address1>Addre1</Address1>",                
            "<FirstName>SomeName</FirstName><LastName>#Brian</LastName><Address1>Addre1</Address1>",
            "<FirstName>SomeName</FirstName><LastName>BrianBrianBrianBrianBrianBrianBrianBrianBrianBrian</LastName><Address1>Addre1</Address1>",
        };

        foreach (var sample in samples)
        {
            bool valid = !regex.IsMatch(sample);
            Console.WriteLine("Valid: {0} Text: {1}", valid, sample);
        }
    }
}

【讨论】:

  • 我试过你的 reg ex 像这样 (.*[^a-zA-Z'\s].*)|(.{41,})。但它也匹配有效的姓氏。我匹配的字符串 SomeNamebrianAddre1.
  • @amz:我回家看看。
  • @amz:现在修复它 - 再看看。
【解决方案2】:

尝试将 RegEx 重写为: &lt;LastName&gt;([a-zA-Z'\s]{0,41})&lt;/LastName&gt; 并在其他代码中使用否定:if (!match.success) ...

【讨论】:

  • 你确定这个 reg ex 匹配 Some123 吗?
  • &lt;LastName&gt;O&amp;amp;Reilly&lt;/LastName&gt;?
  • 不,这两个表达式都不匹配,因为它应该只匹配允许的表达式,其余的必须通过编码来完成。
【解决方案3】:

好的,

我无法一次完成,但如果你分两次完成,我认为它会起作用,首先检查不正确的字符,然后在第二次检查长度,

Match m = Regex.Match(@"<FirstName>SomeName</FirstName><LastName>Some</LastName><Address1>Addre1</Address1>", "<LastName>(.*[^a-zA-Z'\\s].*)</LastName>");

m = Regex.Match(@"<FirstName>SomeName</FirstName><LastName>SomeSomSomeSomeSomeSomeSomeSomeSomeSomeeSomeSomeSomeSomeSomeSomeSome</LastName><Address1>Addre1</Address1>", "<LastName>[a-zA-Z'\\s]{41,}</LastName>");

我还没有检查您提供的所有案例,请检查一下,如果有效,请告诉我。

感谢 Skeet 的更正。[^a-zA-Z'\s]。它确实需要 .* 前后,否则它不会匹配包含特殊字符的名称。

正则表达式模式的第二部分检查长度是否匹配每件事,这就是它不起作用的原因。

祝你好运。

【讨论】:

  • 它正在工作。我会针对更多的名字进行测试,然后告诉你。谢谢。
  • 第二个表达式不适用于超过 40 个字符且包含 spl 的字符串。字符 SomeSomeSomeSomeSomeSomeSomeSomeSomeSomeSome#
  • 当然它不会单独工作,你必须先使用第一个正则表达式检查特殊字符,然后一旦 xml 中的姓氏全部有效并且没有特殊字符,那么你就去第二次通过并使用第二个正则表达式检查长度。
  • 它是否解决了问题,或者它不能是2遍它必须是1遍?
  • 2 遍就可以了。我必须针对一堆名字运行这个。并会尽快回复您。将放弃投票并标记为答案。
猜你喜欢
  • 1970-01-01
  • 2012-11-04
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 2018-06-19
  • 1970-01-01
  • 2010-11-12
相关资源
最近更新 更多