2012-07-06 25 views
6

Po prostu zaczynam rozumieć Wyrażenia regularne i odkryłem, że krzywa uczenia się jest dość stroma. Jednak stackoverflow był ogromnie pomocny w procesie mojego eksperymentowania. Istnieje konkretne słowo, które chciałbym napisać, ale nie znalazłem sposobu, by to zrobić. Chciałbym móc znaleźć dwa słowa w ciągu około 10 słów w dokumencie, a następnie pochylić te słowa, jeśli słowa są więcej niż 10 słów od siebie lub są w innej kolejności Chciałbym, aby makro nie pochyliło się te słowa.Regex Word Makro, które znajduje dwa słowa w zakresie od siebie nawzajem, a następnie pochyla je?

I zostały używając następującego wyrażenia regularnego:

\bPanama\W+(?:\w+\W+){0,10}?Canal\b 

Jednak to tylko pozwala mi manipulować cały ciąg jako całości, w tym przypadkowych słów pomiędzy. Również funkcja .Replace pozwala tylko zastąpić ten ciąg innym ciągiem, który nie zmienia stylów formatowania.

Czy ktoś bardziej doświadczony ma pomysł, jak to zrobić? Czy to możliwe?


EDYCJA: Oto, co mam do tej pory. Mam dwa problemy. Po pierwsze nie wiem, jak wybrać słowa "Panama" i "Kanał" z dopasowanego wyrażenia regularnego i zastąpić tylko te słowa (a nie słowa pośrednie). Po drugie, po prostu nie wiem, jak zastąpić Regexp, który jest dopasowany do innego formatu, tylko inny ciąg tekstu - prawdopodobnie właśnie w wyniku braku znajomości makr Worda.

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 

Ok, dzięki pomocy Tim Williams poniżej mam następujące rozwiązanie razem, to bardziej niż trochę niezdarny pod pewnymi względami i to bynajmniej nie jest czysty regexp ale robi uzyskać Zadanie wykonane. Jeśli ktoś ma lepsze rozwiązanie lub pomysł o tym, jak to zrobić, byłbym zafascynowany, słysząc to. Ponownie, moja brute wymuszanie zmian z poszukiwaniem i zastąpienie funkcji jest trochę żenująco surowy, ale przynajmniej to działa ...

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 
+0

Obiekt Dopasuj ma właściwość Indeks, która informuje, gdzie w tekście wystąpiło dopasowanie. Możesz użyć tego do adresowania określonych zakresów, aby zmienić ich formatowanie. Jeśli zaktualizujesz pytanie, aby pokazać istniejący kod, ktoś może zadzwonić z sugerowanymi zmianami. –

+0

pokaż mi listę słów, na których uruchamiasz wyrażenie regularne. – jared

+1

Czy "słowa to więcej niż 10 słów" lub "wyrazy to więcej niż 10 liter" lub "zdania to więcej niż 10 słów"? – Cylian

Odpowiedz

6

jestem daleko bycia przyzwoity programista Worda, ale to może ci zacząć.

EDYCJA: zaktualizowano, aby dołączyć sparametryzowaną wersję.

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 
+0

To świetnie się spisuje, znajdując tekst i zmieniając jego format. Prawdziwym problemem, jaki miałem, jest to, że wszystkie makra, które robię, mogą zmieniać tylko całe frazy (zamiast słów "panama" i "Canal"). Na przykład powyższe makro podkreśla wszystkie słowa w "Projekcie Panamy kanału" zamiast tylko 2 i ostatniego słowa tej frazy, może to być po prostu to, co próbuję zrobić jest niemożliwe ... – pavja2

+0

Nie niemożliwe: po prostu nie zrobiłem dla ciebie wszystkiego :-) Wiesz, że pierwszym słowem będzie panama, więc po prostu to zapamiętaj (wiesz gdzie się zaczyna i jak długo). Ostatnim słowem jest kanał, więc też to samo. Po prostu podstawowa matematyka w tym momencie ... –

+0

Tak, naprawdę wymyśliłem sposób obejścia tego - to nie jest zbyt wdzięczne, ale opublikuję to w moim pierwotnym pytaniu, które otrzymuję działając do końca. Dzięki za pomoc, to jest dokładnie to, czego szukałem. – pavja2

0

Jeśli jesteś po prostu robi co 2 słowa w czasie, to pracował dla ja, idąc za twoimi liniami treningowymi.

foo([a-zA-Z0-9]+?){0,10}bar 

Objaśnienie: weźmie słowo 1 (foo), a następnie dopasować wszystko, co jest słowem znaków alfanumerycznych ([a-zA-Z0-9]+?), a następnie za pomocą przestrzeni (), 10 razy ({0,10}), a następnie słowo 2 (bar).

Ten nie obejmuje kropki (nie wiem, czy je chciał), ale jeśli chcesz po prostu dodać . po 0-9 w regex.

Więc (pseudokod) składnia będzie podobny do:

$matches = preg_match_all(); // Your function to get regex matches in an array 

foreach (those matches) { 
    replace(KEY_WORD, <i>KEY_WORD</i>); 
} 

Mam nadzieję, że to pomaga. Testowanie poniżej, podświetliło, co pasowało.


Pracował:

foo this that bar bla

foo economic order war bar

nie działa

Foo ładu gospodarczego. bar wojna

globalnego porządku foo już od kilku wieków, w ciągu tego okresu czasu ludzie ewoluowały różne i skomplikowane relacje handlowe postępowania w sytuacjach takich jak rolnictwo i bar

+0

Być może po prostu coś mi brakuje, moim problemem jest to, że mogę zmienić tylko cały dopasowany regex (to znaczy, że zmienione są również wszystkie słowa między "foo" i "bar"). Nie wiem, jak wziąć mecze, a następnie zmienić tylko słowa "foo" i "bar" bez wpływania na inne słowa w dopasowanym tekście. Dodatkowym problemem, który wynika raczej z braku dobrej znajomości google-fu lub znajomości makr VBA, jest to, że nie wiem, jak zmienić dopasowany format Regexp, jak wymienić zawartość. Zaktualizowałem swoje pytanie za pomocą makra, z którym obecnie pracuję. – pavja2