Regex Word宏,找到彼此相距一定范围内的两个单词,然后将这些单词斜体化?

Regex Word宏,找到彼此相距一定范围内的两个单词,然后将这些单词斜体化?,regex,vba,search,ms-word,Regex,Vba,Search,Ms Word,所以,我刚刚开始理解正则表达式,我发现学习曲线相当陡峭。然而,stackoverflow在我的实验过程中非常有用。有一个特定的单词宏,我想写,但我还没有找到一个方法来做到这一点。我希望能够在文档中找到10个左右单词中的两个单词,然后将这些单词斜体化,如果单词之间的间隔超过10个单词或顺序不同,我希望宏不要将这些单词斜体化 我一直在使用以下正则表达式: \bPanama\W+(?:\w+\W+){0,10}?Canal\b 但是,它只允许我将整个字符串作为一个整体进行操作,包括中间的随机单词。另

所以,我刚刚开始理解正则表达式,我发现学习曲线相当陡峭。然而,stackoverflow在我的实验过程中非常有用。有一个特定的单词宏,我想写,但我还没有找到一个方法来做到这一点。我希望能够在文档中找到10个左右单词中的两个单词,然后将这些单词斜体化,如果单词之间的间隔超过10个单词或顺序不同,我希望宏不要将这些单词斜体化

我一直在使用以下正则表达式:

\bPanama\W+(?:\w+\W+){0,10}?Canal\b
但是,它只允许我将整个字符串作为一个整体进行操作,包括中间的随机单词。另外,.Replace函数只允许我用不同的字符串替换该字符串,而不允许更改格式样式

有没有经验更丰富的人对如何使这项工作有想法?甚至可以这样做吗


编辑:这是我到目前为止的资料。我有两个问题。首先,我不知道如何仅从匹配的正则表达式中选择单词“Panama”和“Canal”,并仅替换这些单词(而不是中间单词)。第二,我只是不知道如何替换一个与不同格式匹配的Regexp,只是一个不同的文本字符串——这可能是因为我不熟悉word宏

Sub RegText()
Dim re As regExp
Dim para As Paragraph
Dim rng As Range
Set re = New regExp
re.Pattern = "\bPanama\W+(?:\w+\W+){0,10}?Canal\b"
re.IgnoreCase = True
re.Global = True
For Each para In ActiveDocument.Paragraphs
  Set rng = para.Range
  rng.MoveEnd unit:=wdCharacter, Count:=-1
  Text$ = rng.Text + "Modified"
  rng.Text = re.Replace(rng.Text, Text$)
Next para
End Sub

好的,感谢下面Tim Williams的帮助,我得到了下面的解决方案,它在某些方面有点笨拙,它绝对不是纯regexp,但它确实完成了任务。如果有人有更好的解决方案或想法来解决这个问题,我会很高兴听到。再一次,我用“搜索和替换”功能强制更改有点让人难堪,但至少它是有效的

Sub RegText()
Dim re As regExp
Dim para As Paragraph
Dim rng As Range
Dim txt As String
Dim allmatches As MatchCollection, m As match
Set re = New regExp
re.pattern = "\bPanama\W+(?:\w+\W+){0,13}?Canal\b"
re.IgnoreCase = True
re.Global = True
For Each para In ActiveDocument.Paragraphs

  txt = para.Range.Text

  'any match?
  If re.Test(txt) Then
    'get all matches
    Set allmatches = re.Execute(txt)
    'look at each match and hilight corresponding range
    For Each m In allmatches
        Debug.Print m.Value, m.FirstIndex, m.Length
        Set rng = para.Range
        rng.Collapse wdCollapseStart
        rng.MoveStart wdCharacter, m.FirstIndex
        rng.MoveEnd wdCharacter, m.Length
        rng.Font.ColorIndex = wdOrange
    Next m
  End If

Next para

Selection.Find.ClearFormatting
Selection.Find.Font.ColorIndex = wdOrange
Selection.Find.Replacement.ClearFormatting
Selection.Find.Replacement.Font.Italic = True
With Selection.Find
    .Text = "Panama"
    .Replacement.Text = "Panama"
    .Forward = True
    .Wrap = wdFindContinue
    .Format = True
    .MatchCase = False
    .MatchWholeWord = False
    .MatchWildcards = False
    .MatchSoundsLike = False
    .MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
Selection.Find.ClearFormatting
Selection.Find.Font.ColorIndex = wdOrange
Selection.Find.Replacement.ClearFormatting
Selection.Find.Replacement.Font.Italic = True
With Selection.Find
    .Text = "Canal"
    .Replacement.Text = "Canal"
    .Forward = True
    .Wrap = wdFindContinue
    .Format = True
    .MatchCase = False
    .MatchWholeWord = False
    .MatchWildcards = False
    .MatchSoundsLike = False
    .MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll

Selection.Find.ClearFormatting
Selection.Find.Font.ColorIndex = wdOrange
Selection.Find.Replacement.ClearFormatting
Selection.Find.Replacement.Font.ColorIndex = wdBlack
With Selection.Find
    .Text = ""
    .Replacement.Text = ""
    .Forward = True
    .Wrap = wdFindContinue
    .Format = True
    .MatchCase = False
    .MatchWholeWord = False
    .MatchWildcards = False
    .MatchSoundsLike = False
    .MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub

如果你一次只做两个单词,这对我来说很有效,遵循你的练习路线

foo([a-zA-Z0-9]+? ){0,10}bar
说明: 将抓取单词1(
foo
),然后匹配任何字母数字字符的单词(
[a-zA-Z0-9]+?
),后跟一个空格(
),10次(
{0,10}
),然后匹配单词2(
条)

不包含句号(不知道是否需要),但如果您只想在正则表达式中的
0-9
之后添加

因此,您的(伪代码)语法类似于:

$matches=preg_match_all();//获取数组中正则表达式匹配项的函数
(那些比赛){
替换(关键字,关键字);
}
希望能有帮助。下面的测试突出显示了它匹配的内容


已工作:

这个条上的
foo这个条
blah

foo经济秩序战争栏

不起作用

福经济秩序。战争酒吧


全球食品秩序已经存在了几个世纪,在这段时间里,人们已经形成了不同而复杂的贸易关系,处理诸如农业和酒吧之类的情况。我离成为一个像样的文字程序员还有很长的路要走,但这可能会让你开始

编辑:更新为包含参数化版本

Sub Tester()

    HighlightIfClose ActiveDocument, "panama", "canal", wdBrightGreen
    HighlightIfClose ActiveDocument, "red", "socks", wdRed

End Sub


Sub HighlightIfClose(doc As Document, word1 As String, _
                     word2 As String, clrIndex As WdColorIndex)
    Dim re As RegExp
    Dim para As Paragraph
    Dim rng As Range
    Dim txt As String
    Dim allmatches As MatchCollection, m As match

    Set re = New RegExp
    re.Pattern = "\b" & word1 & "\W+(?:\w+\W+){0,10}?" _
                 & word2 & "\b"
    re.IgnoreCase = True
    re.Global = True

    For Each para In ActiveDocument.Paragraphs

      txt = para.Range.Text

      'any match?
      If re.Test(txt) Then
        'get all matches
        Set allmatches = re.Execute(txt)
        'look at each match and hilight corresponding range
        For Each m In allmatches
            Debug.Print m.Value, m.FirstIndex, m.Length
            Set rng = para.Range
            rng.Collapse wdCollapseStart
            rng.MoveStart wdCharacter, m.FirstIndex
            rng.MoveEnd wdCharacter, Len(word1)
            rng.HighlightColorIndex = clrIndex
            Set rng = para.Range
            rng.Collapse wdCollapseStart
            rng.MoveStart wdCharacter, m.FirstIndex + (m.Length - Len(word2))
            rng.MoveEnd wdCharacter, Len(word2)
            rng.HighlightColorIndex = clrIndex
        Next m
      End If

    Next para

End Sub

Match对象有一个Index属性,它告诉您匹配发生在文本中的什么位置。您可以使用它来处理特定范围,以更改其格式。如果你更新你的问题以显示你现有的代码,有人可能会加入建议的更改。显示你正在运行正则表达式的单词列表。是
单词多于10个单词
还是
单词多于10个字母
或者
句子多于10个单词
?@TimWilliams我会查看匹配属性并无论我有机会发布什么,我从来没有真正做过比基本VBA更多的事情,所以我不确定我能从中得到多少。@jared我没有一个具体的单词列表,而是一堆新闻文章,我希望能够将可能不相邻的特定单词对斜体化,例如“global”在单词“war”的10个单词中,也许我遗漏了一些东西,我的问题是我只能更改整个正则表达式匹配(即“foo”和“bar”之间的所有单词也都被更改)。我不知道如何进行匹配,然后只更改单词“foo”和“bar”,而不影响匹配文本中的任何其他单词。第二个问题更多的是由于我没有很好的GoogleFu或者不熟悉VBA宏,我不知道如何更改匹配的Regexp格式,只知道如何替换内容。我用目前正在使用的宏更新了我的问题。这在查找文本和更改其格式方面做得很好,我遇到的真正问题是,我所做的所有宏只能更改整个短语(而不仅仅是单词“巴拿马”和“运河”)。例如,上面的宏突出显示了“巴拿马运河项目”中的所有单词,而不是该短语的最后一个单词,它可能只是我试图做的是不可能的…不是不可能的:我只是没有为你做整件事:-)你知道第一个单词将是巴拿马,所以请点亮它(你知道它从哪里开始,它的长度).最后一个词是canal,所以请把它也亮起来。在这一点上只有基本的数学…是的,我实际上想出了一个解决方法-它不是很优雅,但我会把它贴在我原来的第一个问题中,我一直都在用它。谢谢你的帮助,这正是我想要的。用我的解决方案更新了我的帖子这似乎一直有效,但也很难看,然而这是我能想到的唯一可行的方法,可以不费吹灰之力地改变宏观中的词汇(就像我在寻找尼采和认识论,而不是巴拿马和运河)。非常感谢
Sub Tester()

    HighlightIfClose ActiveDocument, "panama", "canal", wdBrightGreen
    HighlightIfClose ActiveDocument, "red", "socks", wdRed

End Sub


Sub HighlightIfClose(doc As Document, word1 As String, _
                     word2 As String, clrIndex As WdColorIndex)
    Dim re As RegExp
    Dim para As Paragraph
    Dim rng As Range
    Dim txt As String
    Dim allmatches As MatchCollection, m As match

    Set re = New RegExp
    re.Pattern = "\b" & word1 & "\W+(?:\w+\W+){0,10}?" _
                 & word2 & "\b"
    re.IgnoreCase = True
    re.Global = True

    For Each para In ActiveDocument.Paragraphs

      txt = para.Range.Text

      'any match?
      If re.Test(txt) Then
        'get all matches
        Set allmatches = re.Execute(txt)
        'look at each match and hilight corresponding range
        For Each m In allmatches
            Debug.Print m.Value, m.FirstIndex, m.Length
            Set rng = para.Range
            rng.Collapse wdCollapseStart
            rng.MoveStart wdCharacter, m.FirstIndex
            rng.MoveEnd wdCharacter, Len(word1)
            rng.HighlightColorIndex = clrIndex
            Set rng = para.Range
            rng.Collapse wdCollapseStart
            rng.MoveStart wdCharacter, m.FirstIndex + (m.Length - Len(word2))
            rng.MoveEnd wdCharacter, Len(word2)
            rng.HighlightColorIndex = clrIndex
        Next m
      End If

    Next para

End Sub