代码之家  ›  专栏  ›  技术社区  ›  VirtuosiMedia

变量顺序regex语法

  •  6
  • VirtuosiMedia  · 技术社区  · 15 年前

    有没有一种方法可以表明两个或多个regex短语可以以任何顺序出现?例如,XML属性可以以任何顺序写入。假设我有以下XML:

    <a href="home.php" class="link" title="Home">Home</a>
    <a href="home.php" title="Home" class="link">Home</a>
    

    我该如何写一个匹配项来检查类和标题并适用于这两种情况?我主要在寻找允许我按任何顺序检查的语法,而不仅仅是匹配类和标题。除了包含这两种组合并用“”连接之外,还有其他方法吗?

    编辑 :我的首选是在一个regex中完成它,因为我正在用编程方法构建它,并且还要对它进行单元测试。

    7 回复  |  直到 11 年前
        1
  •  8
  •   paxdiablo    11 年前

    不,我相信用一个RE来做这件事的最好方法和你描述的完全一样。不幸的是,当您的XML可以有5个不同的属性时,它会变得非常混乱,给您一个 大的 要检查的不同资源数。

    另一方面,我根本不会用re来做这个,因为它们不应该是编程语言。使用XML处理库的老式方法有什么问题?

    如果你是 必修的 要使用Re,这个答案可能没有多大帮助,但我相信使用合适的工具来完成这项工作。

        2
  •  5
  •   Leigh josh poley    11 年前

    你考虑过xpath吗?(属性顺序不重要)

    //a[@class and @title]
    

    将同时选择 <a> 节点为有效匹配。唯一需要注意的是,输入必须是XHTML(格式良好的XML)。

        3
  •  4
  •   Alan Moore Chris Ballance    15 年前

    您可以为每个属性创建一个lookahead,并将它们插入整个标记的regex中。例如,标记的regex可以是

    <a\b[^<>]*>
    

    如果您在XML上使用它,可能需要更详细的说明。这个基regex本身将匹配一个属性为零或更多的标记。然后为要匹配的每个属性添加一个查找头:

    (?=[^<>]*\s+class="link")
    (?=[^<>]*\s+title="Home")
    

    这个 [^<>]* 让它向前扫描属性,但不会让它超出闭合角括号。在lookahead中匹配前导空格有两个目的:它比在基regex中匹配更灵活,而且它确保我们匹配的是整个属性名。结合起来,我们得到:

    <a\b(?=[^<>]*\s+class="link")(?=[^<>]*\s+title="Home")[^<>]+>[^<>]+</a>
    

    当然,为了清晰起见,我做了一些简单的假设。我不允许等号周围有空格,属性值周围有单引号或无引号,或属性值中有尖括号(我听说这是合法的,但我从未见过这样做)。如果需要的话,堵住这些漏洞会使regex更丑,但不需要更改基本结构。

        4
  •  2
  •   Josh Bush    15 年前

    可以使用命名组从标记中提取属性。运行regex,然后在组中循环执行所需的任何测试。

    类似这样的情况(未测试,使用.NET regex语法和\w for word字符和\s for whitespace):

    <a ((?<key>\w+)\s?=\s?['"](?<value>\w+)['"])+ />
    
        5
  •  0
  •   Daniel Brückner Pradip    15 年前

    第一个特别的解决方案可能是执行以下操作。

    ((class|title)="[^"]*?" *)+
    

    这远不是完美的,因为它允许每个属性发生多次。我可以想象这可以用断言来解决。但是,如果您只想提取属性,这可能已经足够了。

        6
  •  0
  •   Kibbee    15 年前

    最简单的方法是编写一个regex来获取 <a .... > 然后再写两个正则表达式来拉出类和标题。虽然您可以用一个regex来完成它,但是它非常复杂,而且可能更容易出错。

    用一个正则表达式,你需要

    <a[^>]*((class="([^"]*)")|(title="([^"]*)"))?((title="([^"]*)")|(class="([^"]*)"))?[^>]*>
    

    这只是一个第一手的猜测,没有检查它是否有效。更容易分治问题。

        7
  •  0
  •   rampion    15 年前

    如果要匹配一组元素的排列,可以使用反向引用和零宽度的组合 负正向匹配。

    假设您想要匹配这六行中的任何一行:

    123-abc-456-def-789-ghi-0AB
    123-abc-456-ghi-789-def-0AB
    123-def-456-abc-789-ghi-0AB
    123-def-456-ghi-789-abc-0AB
    123-ghi-456-abc-789-def-0AB
    123-ghi-456-def-789-abc-0AB
    

    您可以使用以下regex执行此操作:

    /123-(abc|def|ghi)-456-(?!\1)(abc|def|ghi)-789-(?!\1|\2)(abc|def|ghi)-0AB/
    

    后面的参考文献( \1 , \2 ,让您参考以前的匹配,以及零 宽度向前匹配( (?!...) )让您否定位置匹配,并说如果 此位置包含匹配项。将两者结合起来确保你的匹配是合法的排列 对于给定的元素,每个可能性只发生一次。

    例如,在Ruby中:

    input = <<LINES
    123-abc-456-abc-789-abc-0AB
    123-abc-456-abc-789-def-0AB
    123-abc-456-abc-789-ghi-0AB
    123-abc-456-def-789-abc-0AB
    123-abc-456-def-789-def-0AB
    123-abc-456-def-789-ghi-0AB
    123-abc-456-ghi-789-abc-0AB
    123-abc-456-ghi-789-def-0AB
    123-abc-456-ghi-789-ghi-0AB
    123-def-456-abc-789-abc-0AB
    123-def-456-abc-789-def-0AB
    123-def-456-abc-789-ghi-0AB
    123-def-456-def-789-abc-0AB
    123-def-456-def-789-def-0AB
    123-def-456-def-789-ghi-0AB
    123-def-456-ghi-789-abc-0AB
    123-def-456-ghi-789-def-0AB
    123-def-456-ghi-789-ghi-0AB
    123-ghi-456-abc-789-abc-0AB
    123-ghi-456-abc-789-def-0AB
    123-ghi-456-abc-789-ghi-0AB
    123-ghi-456-def-789-abc-0AB
    123-ghi-456-def-789-def-0AB
    123-ghi-456-def-789-ghi-0AB
    123-ghi-456-ghi-789-abc-0AB
    123-ghi-456-ghi-789-def-0AB
    123-ghi-456-ghi-789-ghi-0AB
    LINES
    
    # outputs only the permutations
    puts input.grep(/123-(abc|def|ghi)-456-(?!\1)(abc|def|ghi)-789-(?!\1|\2)(abc|def|ghi)-0AB/)
    

    对于五个元素的排列,它是:

    /1-(abc|def|ghi|jkl|mno)-
     2-(?!\1)(abc|def|ghi|jkl|mno)-
     3-(?!\1|\2)(abc|def|ghi|jkl|mno)-
     4-(?!\1|\2|\3)(abc|def|ghi|jkl|mno)-
     5-(?!\1|\2|\3|\4)(abc|def|ghi|jkl|mno)-6/x
    

    对于您的示例,regex将是

    /<a href="home.php" (class="link"|title="Home") (?!\1)(class="link"|title="Home")>Home<\/a>/