编辑1 - 解决方案
使用下面发布的模式作为开头,我稍微编辑了表达式,以确保它捕获短语和单词,然后我们只丢弃任何以.
Sub test()
Application.EnableEvents = False
getAllTitleCasePhrases Range("D4", Range("D4").End(xlDown))
Application.EnableEvents = True
End Sub
Private Sub getAllTitleCasePhrases(rng As Range)
If objRegex Is Nothing Then Set objRegex = New RegExp
With objRegex
.Global = True
.Pattern = "(\.\s*[A-Z][\w,']*)|([A-Z][\w,']*\s?)+"
End With
Dim cll As Range, testResult As Object, resultsStr As String
For Each cll In rng
Set testResult = objRegex.Execute(cll.Value2)
If testResult.Count > 0 Then
Dim i As Long, j As Long
For i = 0 To testResult.Count - 1
If Left$(testResult(i), 1) <> "." Then
resultsStr = resultsStr & WorksheetFunction.Trim(testResult(i).Value) & ", "
End If
Next i
End If
If Len(resultsStr) > 0 Then resultsStr = Left(resultsStr, Len(resultsStr) - 2)
cll.Offset(0, 1).Value2 = resultsStr
resultsStr = vbNullString
Next cll
Set objRegex = Nothing
End Sub
问题
我想自动创建一个合同中所有已定义术语的列表,这样我就可以轻松地检查它们确实在某处确实有相应的定义。合同中的定义条款用Title Case或ALL CAPS编写,我在下面列出了一些测试用例和预期输出。
我的方法是使用正则表达式模式扫描文档并挑选出适合这些模式的所有单词或短语。通过使用答案here和here,此部分非常简单。我遇到的问题是:(1)这仍然会捕捉到完全停止后大写的单词和(2)最后一个单词末尾的空格包含在匹配中。
请注意我下面的实现是在Excel VBA中,但它是我真正感兴趣的正则表达式。如果(1)和(2)都无法一起实现,(1)更重要,因为我可以剥离在代码中的其他地方尾随空格。
当前解决方案
(^[^\.])?([A-Z]+[a-z,']*\s?)+
说明:
(^[^\.])?
- 如果在字符串的开头有句号,请忽略它
[A-Z]+
- 匹配以至少一个首字母开头的单词
[a-z,']*
- 单词可以以任意数量的非大写字母结尾,并且允许使用撇号
([A-Z]+[a-z,']*\s?)+
- 重复此模式以捕捉多个单词
测试用例
实施
(注意测试用例列表从单元格D4
开始)
Option Explicit
Private objRegex As RegExp
Sub test()
getAllTitleCasePhrases Range("D4", Range("D4").End(xlDown))
End Sub
Private Sub getAllTitleCasePhrases(rng As Range)
If objRegex Is Nothing Then Set objRegex = New RegExp
With objRegex
.Global = True
.Pattern = "(^[^\.])?([A-Z]+[a-z,']*\s?)+"
End With
Dim cll As Range, testResult As Object, resultsStr As String
For Each cll In rng
Set testResult = objRegex.Execute(cll.Value2)
If testResult.Count > 0 Then
Dim i As Long
For i = 0 To testResult.Count - 1
resultsStr = resultsStr & testResult(i).Value & ", "
Next i
End If
If Len(resultsStr) > 0 Then resultsStr = Left(resultsStr, Len(resultsStr) - 2)
cll.Offset(0, 1).Value2 = resultsStr
resultsStr = vbNullString
Next cll
Set objRegex = Nothing
End Sub