使用正则表达式识别文档内的法语格式的数字

时间:2011-11-21 10:26:07

标签: regex vba ms-word word-vba

我有一份文件,其中包含各种格式的数字,法语,英语,自定义格式。

我想要一个只能以法语格式捕获数字的正则表达式。

这是我要捕获的完整数字列表(d表示数字,小数点分隔符为逗号,,千位分隔符为空格)

d,d d,dd   d,ddd

dd,d   dd,dd   dd,ddd

ddd,d   ddd,dd   ddd,ddd

d ddd,d   d ddd,dd   d ddd,ddd

dd ddd,d  dd ddd,dd  dd ddd,ddd

ddd ddd,d  ddd ddd,dd  ddd ddd,ddd

d ddd ddd,d...

dd ddd ddd,d...

ddd ddd ddd,d...

这是我的正则表达式

(\d{1,3}\s(\d{3}\s)*\d{3}(\,\d{1,3})?|\d{1,3}\,\d{1,3})

捕获上面的法语格式,因此我走在正确的轨道上,但也有d,ddd.dd之类的数字(因为它捕获d,ddd)或d,ddd,ddd(因为它捕获d,ddd })。

我应该在正则表达式中添加什么内容?

我的VBA代码:

Sub ChangeNumberFromFRformatToENformat()

Dim SectionText As String
Dim RegEx As Object, RegC As Object, RegM As Object
Dim i As Integer

Set RegEx = CreateObject("vbscript.regexp")
With RegEx
    .Global = True
    .MultiLine = False
    .Pattern = "(\d{1,3}\s(\d{3}\s)*\d{3}(\,\d{1,3})?|\d{1,3}\,\d{1,3})"
    ' regular expression used for the macro to recognise FR formated numners
    End With

For i = 1 To ActiveDocument.Sections.Count()

    SectionText = ActiveDocument.Sections(i).Range.Text

    If RegEx.test(SectionText) Then
        Set RegC = RegEx.Execute(SectionText)
        ' RegC regular expresion matches collection, holding french format numbers

        For Each RegM In RegC

            Call ChangeThousandAndDecimalSeparator(RegM.Value)

        Next 'For Each RegM In RegC

        Set RegC = Nothing
        Set RegM = Nothing

    End If

Next 'For i = 6 To ActiveDocument.Sections.Count()

Set RegEx = Nothing

End Sub

用户stema,给了我一个很好的解决方案。正则表达式应该是:

; | \ d {1,3}(小于= ^ \ S')(?:\ S \ d {3})*?(?:\,\ d {1,3})( ?= \ S | $)

但是VBA抱怨正则表达式没有未转义的字符。我在(?:\ d {3})之间找到了一个(?:\ d {3}),这是一个空白字符,所以我可以用\ s替换它。我认为第二个(?:,\ d {1,3})介于?:和\ d之间,逗号字符,如果我转义它将是\,。

所以正则表达式现在是(?< = ^ | \ s)\ d {1,3}(?:\ s \ d {3})*(?:\,\ d {1,3}) ?(?= \ s | $)并且它在RegExr中工作正常但我的VBA代码不接受它。

邮政新线: 我刚刚发现VBA不同意正则表达式的这一序列?< = ^

2 个答案:

答案 0 :(得分:2)

这个怎么样?

\b\d{1,3}(?: \d{3})*(?:,\d{1,3})?\b

here on Regexr

\b是字边界

首先(\d{1,3})匹配1到3位数,然后可以有0个或更多个前导空格组,后跟3个数字((?: \d{3})*),最后可以有一个可选的分数部分((?:,\d{1,3})?

修改

如果你想避免1,111.1,那么\b锚点对你不利。试试这个:

(?<=^|\s)\d{1,3}(?: \d{3})*(?:,\d{1,3})?(?=\s|$)

Regexr

这个正则表达式现在需要一个空格或前面的字符串的开头,以及要匹配的数字之后的空格或字符串的结尾。

编辑2:

由于不支持外观,您可以更改为

(?:^|\s)\d{1,3}(?: \d{3})*(?:,\d{1,3})?(?=\s|$)

这在字符串的开头没有任何变化,但是如果数字以前导空格开头,则现在包含在匹配中。如果匹配的结果首先用于某些东西,则必须剥离前导空格(我非常确定VBA确实有一个方法(尝试trim()))。

答案 1 :(得分:0)

如果您逐行阅读,可以考虑在正则表达式中添加锚点^$),这样您最终会得到类似的结果:

^(\d{1,3}\s(\d{3}\s)*\d{3}(\,\d{1,3})?|\d{1,3}\,\d{1,3})$

这指示RegEx引擎从行的开头直到最后开始匹配。