如何为更严格的Anchor标记构建正则表达式

时间:2013-08-16 21:41:35

标签: html regex html-parsing

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

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

这允许锚标记具有titlehref属性,但不允许其他任何属性。我还想添加target但是我试过的任何东西都不起作用。

  1. 该链接必须包含href属性。
  2. 它可以包含title属性,但不必。
  3. 它可以包含target属性,但也不必包含。
  4. 如何修改满足上述所有条件的正则表达式。

3 个答案:

答案 0 :(得分:4)

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

将锚标记与您的要求相匹配,您可以使用下面的正则表达式。它使用反向引用来跟踪最多一个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

答案 1 :(得分:1)

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)将失败,因为&#39; foo&#39;是一个不允许的属性(未在allowedAttrs中定义)。

这种方法的好处在于你

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

我留下isValidURL()供您定义。

答案 2 :(得分:1)

让我们更容易:

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