【问题标题】:How to build Regular Expression for more strict Anchor tag如何为更严格的 Anchor 标签构建正则表达式
【发布时间】:2013-08-16 21:41:34
【问题描述】:

我正在尝试限制 Markdown 编辑器的 HTML 中锚标记可以使用的一些属性。这就是我现在拥有的:

/^(<a\shref="((https?|ftp):\/\/|\/)[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+"(\stitle="[^"<>]+")?\s?>|<\/a>)$/i

这允许带有titlehref 属性的锚标记,但仅此而已。我还想添加target,但无论我尝试什么都没有用。

  1. 链接必须包含href 属性。
  2. 它可以包含title 属性,但不是必须的。
  3. 它可以包含target 属性,但不是必须的。

如何修改满足以上所有条件的正则表达式。

【问题讨论】:

  • 你使用什么语言?
  • title = "xyz"(即= 周围的空格)呢?如果属性以其他顺序出现怎么办?
  • 您不应该使用正则表达式解析 HTML。
  • 不要使用正则表达式解析 HTML。使用适当的 HTML 解析模块。 您无法使用正则表达式可靠地解析 HTML,并且您将面临悲伤和挫败感。一旦 HTML 与您的期望发生变化,您的代码就会被破坏。有关如何使用已经编写、测试和调试的 PHP 模块正确解析 HTML 的示例,请参阅 htmlparsing.com/php

标签: html regex html-parsing


【解决方案1】:

通常,正则表达式并不是解析某些语言的最佳工具。另一方面,如果你只是想匹配一个孤立的锚标记,那么解析器可能有点太多了,而正则表达式可以做得很好。

根据您的要求匹配锚标记,您可以使用下面的正则表达式。它使用反向引用来跟踪最多一个title和一个target(重复属性),至少/最多一个href

^(<a(?=[^>]*?(\s+href="((https?|ftp):\/\/|\/)[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+")[^>]*>)(?=([^>]*?(\s+title="[^"<>]+"))?[^>]*>)(?=([^>]*?(\s+target="[^"<>]+"))?[^>]*>)(\2(\6\8?)?|\2\8\6?|\6\2\8?|\8\2\6?|\6\8\2|\8\6\2)\s*>[^<]*</a>)$

查看demo here,以及数十个测试用例,您可以对解决方案进行验证测试。

观察这个正则表达式并没有那么复杂(“丑陋”的部分是 URL,真的),但它非常全面并且照顾到:

  • 一个强制性的href 属性
  • 可选的title 属性
  • 可选的target 属性
  • 不允许使用其他类型的属性(尽管自定义和添加支持很容易)
  • 它们之间有任意数量的空格
  • 他们可以按任何顺序
  • 最多可以有一个href、一个title和一个target

【讨论】:

  • 你能告诉我你是否测试过它吗?不幸的是,它没有用。
  • 如何使属性的顺序灵活?
  • 好的,更新了答案,修改了正则表达式。检查示例。
  • 非常感谢您的时间和精力!
  • 嘿,我添加了另一个正则表达式,是最后一个稍微复杂的版本。 “奖励”是它处理重复的属性。查看演示以获取一些示例。另外,如果你愿意,我可以为他们做一个解释。干杯。
【解决方案2】:

RegEx-en 他们自己并不擅长这种事情。

我会这样做:

function validateAnchor(anchor){

    var match,
        name,
        value,
        test,
        attrRE=/\s([a-z]+)(?:\s*=\s*"([^"]+))?"/gi, // matches one tag attribute
        allowedAttrs={ // attributes must appear here to be considered legal
          href:{
            isValid:function(val){
               return isValidURL(val);
            }
          },
          title:{
            isValid:function(val){
                return true;
            }
          },
          target:{
            isValid:function(val){
              return true;
            }
          }
        },
        result=true;

    while(match=attrRE.exec(anchor)){

        name=match[1].toLowerCase(); // lowerCase to match our allowedAttrs keys
        value=match[2]||'';          // optional

        // must have a name
        if(!name){
            console.log('no name for this attr - should not happen!');
            result=false;
            break;
        }

        // and must exist in allowedAttrs
        if(test=allowedAttrs[name]) {
            console.log('unknown attr');
            result=false;
            break;
        }

        // if it has a value and there is am isValid function.
        if(value && 'function'==typeof(attr.isValid)){
            if(!attr.isValid(value)){ // which fails!
                result=false;
                break;
            }
        }
    }
    return result;
}

所以,给定的:

var anchor='<a href=\"...\" target = \"...\" foo >';

validateAnchor(anchor) 将失败,因为 'foo' 是一个不允许的属性(未在 allowedAttrs 中定义)。

这种方法的好处是你

  • 不需要每次需要接受新属性时都修改你的RE,
  • 可以有无价值的属性

我把 isValidURL() 留给你定义。

【讨论】:

    【解决方案3】:

    让我们让它变得更简单:

    /<a(?=.*href="((ht|f)tps?:\/)?\/.*")\s*((href|title|target)="[^"]*"\s*)*>[^<]*</a>/
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 2015-04-01
      • 1970-01-01
      • 2022-11-11
      • 1970-01-01
      • 2018-03-02
      • 1970-01-01
      相关资源
      最近更新 更多