我正在尝试清理HTML输入字段。我想保留一些标签,但不是全部,所以我不能在阅读元素值时使用.text()
。我在Safari中使用JavaScript中的正则表达式时遇到了一些麻烦。这是代码片段(我从另一个SO线程答案中复制了这一部分正则表达式):
aString.replace (/<\s*a.*href=\"(.*?)\".*>(.*?)<\/a>/gi, '$2 (Link->$1)' ) ;
以下是失败的示例输入:
<a href="http://blar.pirates.net/black/ship.html">Go here please.</a></p><p class="p1"><a href="http://blar.pirates.net/black/ship.html">http://blar.pirates.net/black/ship.html</a></p>
这个想法是,href将被拉出并输出为原始文本旁边的文本。所以上面的输出最终应该是这样的:
Go here please (Link->http://blar.pirates.net/black/ship.html)
http://blar.pirates.net/black/ship.html (Link->http://blar.pirates.net/black/ship.html)
然而,正则表达式在第一场比赛中一直抓到第二个</a>
标签,所以我输掉了第一行输出。 (实际上,只要锚元素相邻,它就会抓住列表中的那么远。)输入是一个长字符串,不是用CR / LF或其他任何东西分割。
我尝试使用这样的非贪婪标志(注意第二个问号):
/<\s*a.*href=\"(.*?)\".*?>(.*?)<\/a>/ig
但这似乎没有改变任何东西(至少在我尝试过的少数测试人员/解析器中,其中一个在这里:http://refiddle.com)。还尝试了/U
标志,但没有帮助(或者这些解析器无法识别它)。
有什么建议吗?
答案 0 :(得分:4)
模式中存在一些错误并可能有所改进:
/<
\s* # not needed (browsers don't recognize "< a" as an "a" tag)
a # if you want to avoid a confusion between an "a" tag and the start
# of an "abbr" tag, you can add a word boundary or better, a "\s+" since
# there is at least one white character after.
. # The dot match all except newlines, if you have an "a" tag on several
# lines, your pattern will fail. Since Javascript doesn't have the
# "singleline" or "dotall" mode, you must replace it with `[\s\S]` that
# can match all characters (all that is a space + all that is not a space)
* # Quantifiers are greedy by default. ".*" will match all until the end of
# the line, "[\s\S]*" will match all until the end of the string!
# This will cause to the regex engine a lot of backtracking until the last
# "href" will be found (and it is not always the one you want)
href= # You can add a word boundary before the "h" and put optional spaces around
# the equal sign to make your pattern more "waterproof": \bhref\s*=\s*
\" # Don't need to be escaped, as Markasoftware notices it, an attribute
# value is not always between double quotes. You can have single quotes or
# no quotes at all. (1)
(.*?)
\" # same thing
.* # same thing: match all until the last >
>(.*?)<\/a>/gi
(1) - &gt; 关于引号和href属性值:
要处理单引号,双引号或无引号,您可以使用捕获组和反向引用:
\bhref\s*=\s*(["']?)([^"'\s>]*)\1
细节:
\bhref\s*=\s*
(["']?) # capture group 1: can contain a single, a double quote or nothing
([^"'\s>]*) # capture group 2: all that is not a quote to stop before the possible
# closing quote, a space (urls don't have spaces, however javascript
# code can contain spaces) or a ">" to stop at the first space or
# before the end of the tag if quotes are not used.
\1 # backreference to the capture group 1
请注意,您使用此子模式添加了捕获组,a
标记之间的内容现在位于捕获组中3.请考虑将替换字符串$2
更改为{{1 }}
很好,你可以像这样编写你的模式:
$3
答案 1 :(得分:2)
使用
href="[^"]+"
而不是
href=\"(.*?)\"
基本上这会抓住任何角色,直到它遇到下一个"
虽然以这种方式实现markdown语法之类的东西可能更容易,但您不必担心剥离错误的标记,只需删除所有内容并在显示文本时用其html标记替换掉标记。
例如,在SO上,您只需使用
即可建立链接 [link text](http://linkurl.com)
和替换的正则表达式将是
var displayText = "This is just some text [and this is a link](http://example.com) and then more text";
var linkMarkdown = /\[([^\]]+)\]\(([^\)]+)\)/;
displayText.replace(linkMarkdown,'<a href="$2">$1</a>');
或者使用已经完成转换的已经创建的库。
答案 2 :(得分:1)
谢谢大家的建议;它对我帮助很大,并且有很多改进它的想法。
但我认为我发现原始正则表达式失败的具体原因。卡西米尔的答案触及了它,但在我碰巧遇到这个问题之前我一直都不明白。
我一直在寻找问题的错误位置,在这里:
/<\s*a.*href=\"(.*?)\".*>(.*?)<\/a>/gi
^
我能够通过在a.*hre
区域后插入问号来修复原始查询,如下所示:
/<\s*a.*?href=\"(.*?)\".*>(.*?)<\/a>/gi
^
我计划在此处使用其他建议来进一步改进我的陈述。
- C