RegExp将一个html标记替换为另一个html标记,但有一些例外

时间:2014-01-17 21:27:02

标签: html regex access-vba

我需要更改其他人的一些html标签。

例如,我想更改

<EM></EM> 

标记为

<strong></strong> 

标签,除了

中的单词
<EM> 

标签是等,即:

<EM>et al</EM>.

有没有一种方法可以使用单个替换操作来匹配开始和结束标记内的EM字

<> </> 

或唯一的方法是使用2次替换操作,例如

"(<EM>)(?!et al)", "<strong>"

修改

我在MSAccess中使用VBA。

这是我的UDF:

'--------------------------------------------------------------------
' Name:         RegExpReplace
' Purpose:      Replace text in a string using Regular Expressions.
' Requires:     Microsoft VBScript Regular Expressions 5.5
' Author:       Diego F.Pereira-Perdomo
' Date:         Dec-27-2012
'--------------------------------------------------------------------
Public Function RegExpReplace(ByVal strInput As String, _
                ByVal strPattern As String, _
                ByVal strReplace As String, _
             Optional booIgnCase As Boolean = False, _
              Optional booGlobal As Boolean = True) As String

    Dim oRegExp As RegExp
    Dim strOutp As String

    Set oRegExp = New RegExp
    With oRegExp
        .IgnoreCase = booIgnCase
        .Global = booGlobal
        .pattern = strPattern
        strOutp = .Replace(strInput, strReplace)
        RegExpReplace = strOutp
    End With
    Set oRegExp = Nothing

End Function

2 个答案:

答案 0 :(得分:2)

编辑:

在对VBScript(和VBScript语法)的正则表达式功能进行一些研究之后,最简单的方法似乎是:

Dim re: Set re = New RegExp
re.Pattern = "<em([^>]*)>(?!carmen</em>)([\s\S]*?)</em>"
re.Global = True
re.IgnoreCase = True

Dim str: str = "<em class=""truc"">where</em> in the <eM>world</em> is <em>carmen</em> sandiego?"
Dim rep: rep = "<strong$1>$2</strong>"

MsgBox re.Replace(str, rep)

模式描述:

<em             # literal: <em
([^>]*)         # capture group 1: all characters except > zero or more times
>               # literal: >
(?!carmen</em>) # lookahead assertion: not followed by "carmen</em>"
(               # capture group 2:
    [\s\S]      # all that is a white character + all that is not a white character
                # = all possible characters (including newlines)
    *?          # repeat zero or more times (lazy)
)               # close capture group 2
</em>           # literal: </em>

该模式旨在完全排除“卡门”。如果要排除包含“carmen”的子字符串,则必须对模式进行一些更改,并注意不要检查标记之外的单词(<em>blah blah blah</em> carmen

最简单的方法:

<em([^>]*)>((?:(?!carmen)[\s\S])*?)</em>

请注意,这种方式特别低效,因为正则表达式引擎必须检查每个字符的(?!carmen)

另一种方式:

<em([^>]*)>((?:[^<c]+|c(?!armen)|<(?!/em>))*)</em>

这种模式似乎是一个好主意,但存在问题。当字符串包含结束标记</em>时,一切正常,但如果缺少结束标记,则脚本将因灾难性回溯而崩溃。您可以找到有关此here的更多信息 解决问题的一种方法是使用atomic group (?>..)(其中不允许正则表达式引擎回溯)代替非捕获组(?:..),但使用VBS正则表达式(如Javascript)没有此功能。
但是,您可以使用前瞻,捕获组和反向引用来模拟此功能:(?=(pattern))\1等同于(?>pattern)(因为前瞻是天生的原子)

如果我用这个技巧重写先例模式,我会得到:

<em([^>]*)>((?:(?=([^<c]+|c(?!armen)|<(?!/em>)))\3)*)</em>

答案 1 :(得分:0)

此表达式非常完美。

<(em)>((?!.*?et al).*?)</\1>

所以基本上它捕获了

(em)

在结束标记中使用它

</\1>
即使

之前有字符,

也会排除字符串

(?!.*?et al)

或之后

(?!.*?et al).*?

并捕获结果

((?!.*?et al).*?)

嗯,它的作用越多越好:)

使用我的功能替换这些是一些例子:

实施例1,:

?RegExpReplace("<em>et al</em>", _
"<(em)>((?!.*?et al).*?)</\1>", _
"<strong>$2</strong>", _
True)

结果:

<em>et al</em>

例2:

?RegExpReplace("<em>et al </em>", _
"<(em)>((?!.*?et al).*?)</\1>", _
"<strong>$2</strong>", _
True)

结果:

<em>et al </em>

例3:

?RegExpReplace("<em> et al</em>", _
"<(em)>((?!.*?et al).*?)</\1>", _
"<strong>$2</strong>", _
True)

结果:

<em> et al</em>

Ex.4

?RegExpReplace("<em>et a</em>", _
"<(em)>((?!.*?et al).*?)</\1>", _
"<strong>$2</strong>", _
True)

结果

<strong>et a</strong>

Ex.5

?RegExpReplace("<em>t al</em>", _
"<(em)>((?!.*?et al).*?)</\1>", _
"<strong>$2</strong>", _
True)

结果:

<strong>t al</strong>

请注意在搜索模式和替换字符串中使用反向引用。在搜索模式中,必须使用反斜杠和参考编号;在替换字符串中,必须使用美元符号和参考号。

最后,我不同意RegExp对编辑html(文档或字符串)没有用处或更危险的概念。

使用DOM可以很容易地解析html,毫无疑问,这是推荐的工具。

所以我使用DOM来解析Html,提取不同的部分和RegExp来修改细节。

希望这有助于他人。

此致