2012-07-06 9 views
6

Quindi, sto appena iniziando a capire le espressioni regolari e ho trovato la curva di apprendimento abbastanza ripida. Tuttavia, StackOverflow è stato immensamente utile nel processo della mia sperimentazione. C'è una particolare parola macro che vorrei scrivere ma non ho trovato un modo per farlo. Mi piacerebbe riuscire a trovare due parole entro 10 o più parole l'una dall'altra in un documento e quindi mettere in corsivo quelle parole, se le parole sono più di 10 parole o sono in un ordine diverso vorrei che la macro non fosse in corsivo quelle parole.Regex Word Macro che trova due parole all'interno di un intervallo tra loro e quindi in corsivo di quelle parole?

Sono stato con la seguente espressione regolare:

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

Tuttavia lo lascia solo a me manipolare l'intera stringa nel suo complesso tra cui parole a caso in mezzo. Anche la funzione .Replace mi consente solo di sostituire quella stringa con una stringa diversa, non di cambiare gli stili di formattazione.

Qualcuno con più esperienza ha un'idea su come farlo funzionare? È persino possibile fare?


EDIT: Ecco quello che ho finora. Ci sono due problemi che sto avendo. Innanzitutto non so come selezionare solo le parole "Panama" e "Canale" dall'interno di un'espressione regolare abbinata e sostituire solo quelle parole (e non le parole intermedie). In secondo luogo, non so come sostituire un Regexp che è abbinato a un formato diverso, solo una diversa stringa di testo - probabilmente solo a causa della mancanza di familiarità con i macro di parole.

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, grazie per l'aiuto di Tim Williams sotto ho ottenuto la seguente soluzione insieme, è più di un po 'goffo per certi aspetti e non è affatto regexp puro ma fa ottenere il lavoro fatto. Se qualcuno ha una soluzione o un'idea migliore su come procedere, sarei comunque affascinato dal sentirlo. Ancora una volta, il mio bruta costringendo i cambiamenti con la ricerca e sostituzione funzione è un po 'imbarazzante grezza ma almeno funziona ...

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

L'oggetto Match ha una proprietà Index che indica dove si è verificata la corrispondenza nel testo. Puoi usarlo per indirizzare determinati intervalli per cambiare la loro formattazione. Se aggiorni la tua domanda per mostrare il tuo codice esistente, qualcuno potrebbe intervenire con le modifiche suggerite. –

+0

Mostrami l'elenco di parole su cui stai eseguendo la regex. – jared

+1

E ''' le parole sono più di 10 parole'' o '' le parole sono più di 10 lettere'' o '' le frasi sono più di 10 parole''? – Cylian

risposta

6

Sono molto lontano essendo un programmatore di Word decente, ma questo potrebbe farti iniziare.

MODIFICA: aggiornato per includere una versione parametrizzata.

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

Questo è un ottimo lavoro nel trovare il testo e nel modificarne il formato, il vero problema che ho riscontrato è che tutti i macro che faccio possono solo cambiare intere frasi (invece delle sole parole "panama" e "Canal"). Quindi, per esempio, la macro sopra evidenzia tutte le parole in "Il progetto Panama di un canale" invece di solo la 2 e l'ultima parola di quella frase, potrebbe essere solo che quello che sto cercando di fare è impossibile ... – pavja2

+0

Non impossibile: non ho fatto tutto per te :-) Sai, la prima parola sarà panama, quindi solo hilight (sai dove inizia e la sua lunghezza). L'ultima parola è canal, quindi solo hilight. Solo matematica di base a questo punto ... –

+0

Sì, in realtà ho trovato un modo per aggirarlo - non è molto aggraziato, ma lo metto nella mia domanda iniziale, lo faccio funzionare fino in fondo. Grazie per l'aiuto, questo è esattamente ciò che stavo cercando. – pavja2

0

Se siete dopo solo facendo ogni 2 parole alla volta, questo ha funzionato per io, seguendo le tue linee di pratica.

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

Spiegazione: catturerà parola 1 (foo), poi abbinare tutto ciò che è una parola di caratteri alfanumerici ([a-zA-Z0-9]+?) seguito da uno spazio (), 10 volte ({0,10}), poi parola 2 (bar).

Questo non includono punti fermi (non so se si voleva che li), ma se si desidera aggiungere solo . dopo 0-9 nel regex.

Così il vostro (pseudocodice) sintassi sarà simile a:

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

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

Speriamo che aiuta. Testare di seguito, ha evidenziato ciò che corrisponde.


funzionato:

Il foo this that bar bla

Il foo economic order war bar

non ha funzionato

L'ordine economico foo. bar guerra

L'ordine foo globale è stato intorno per molti secoli, in questo periodo di tempo le persone si sono evoluti diversi e intricati rapporti commerciali che si occupano di situazioni come l'agricoltura e il bar

+0

Forse mi manca qualcosa, il mio problema è che posso solo cambiare l'intera espressione regolare (ad esempio tutte le parole tra "foo" e "bar" sono anche cambiate). Non so come prendere le corrispondenze e quindi modificare solo le parole "foo" e "bar" senza influenzare altre parole all'interno del testo corrispondente. Un problema secondario che è più un risultato del mio non avere google-fu o familiarità con i macro VBA è che non so come modificare un formato di Regexp corrispondente, solo come sostituire il contenuto. Ho aggiornato la mia domanda con la macro con cui sto attualmente lavorando. – pavja2

Problemi correlati