2012-07-06 47 views
6

Por lo tanto, estoy empezando a entender expresiones regulares y he encontrado la curva de aprendizaje bastante empinada. Sin embargo, stackoverflow ha sido inmensamente útil en el proceso de mi experimentación. Hay una macro de palabras particular que me gustaría escribir pero no he encontrado una manera de hacerlo. Me gustaría poder encontrar dos palabras dentro de 10 o más palabras entre sí en un documento y luego ponerlas en cursiva, si las palabras están separadas más de 10 palabras o están en un orden diferente Me gustaría que la macro no se ponga en cursiva esas palabras.¿Macro de palabra Regex que encuentra dos palabras dentro de un rango el uno del otro y luego pone en cursiva esas palabras?

He estado usando la siguiente expresión regular:

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

Sin embargo, sólo me permite manipular la cadena entera como un todo incluyendo palabras al azar en el medio. Además, la función .Replace solo me permite reemplazar esa cadena con una cadena diferente y no cambiar los estilos de formateo.

¿Alguna persona más experimentada tiene una idea de cómo hacer que esto funcione? ¿Es posible hacerlo?


EDITAR: Esto es lo que tengo hasta ahora. Hay dos problemas que estoy teniendo. Primero, no sé cómo seleccionar solo las palabras "Panamá" y "Canal" dentro de una expresión regular coincidente y reemplazar solo esas palabras (y no las palabras intermedias). En segundo lugar, simplemente no sé cómo reemplazar una Regexp que se combina con un formato diferente, solo una cadena de texto diferente, probablemente solo como resultado de la falta de familiaridad con las macros de palabras.

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, gracias a la ayuda de Tim Williams a continuación me dio la siguiente solución juntos, es más que un poco torpe en algunos aspectos y que no es en absoluto expresión regular pura pero hace obtener el trabajo hecho. Si alguien tiene una mejor solución o idea acerca de cómo hacer esto, me encantaría escucharlo. Una vez más, mi fuerza bruta sobre los cambios con la función de búsqueda y reemplazar es un poco embarazoso crudo, pero al menos funciona ...

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

El objeto Match tiene una propiedad Index que le indica en qué parte del texto se produjo la coincidencia. Puede usar eso para abordar rangos particulares para cambiar su formato. Si actualiza su pregunta para mostrar su código actual, alguien puede responder con los cambios sugeridos. –

+0

muéstrame la lista de palabras con las que ejecutas la expresión regular. – jared

+1

¿Son '' las palabras son más de 10 palabras'' o '' las palabras tienen más de 10 letras'' o '' las oraciones son más de 10 palabras''? – Cylian

Respuesta

6

estoy muy lejos de ser un programador de Word decente, pero esto podría ayudarlo a comenzar.

EDITAR: actualizado para incluir una versión parametrizada.

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

Hace un gran trabajo para encontrar el texto y cambiar su formato, el verdadero problema que he tenido es que todas las macros que hago solo pueden cambiar frases completas (en lugar de solo las palabras "panama" y "Canal"). Entonces, por ejemplo, la macro de arriba resalta todas las palabras en "El proyecto de Panamá de un canal" en lugar de solo la 2 y la última palabra de esa frase, podría ser que lo que estoy tratando de hacer es imposible ... – pavja2

+0

No imposible: simplemente no hice todo por ti :-) Sabes que la primera palabra será panama, por lo tanto, hilight that (ya sabes dónde comienza, y su longitud). La última palabra es canal, por lo que también creo eso. Solo matemáticas básicas en este punto ... –

+0

Sí, de hecho descubrí una forma de evitarlo, no es muy elegante, pero lo publico en mi pregunta original, y lo hago funcionar todo el tiempo. Gracias por la ayuda, esto es más o menos exactamente lo que estaba buscando. – pavja2

0

Si lo que busca es simplemente haciendo cada 2 palabras a la vez, esto funcionó para yo, siguiendo tus líneas de práctica.

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

Explicación: se agarrar palabra 1 (foo), a continuación, coincide con cualquier cosa que es una palabra de caracteres alfanuméricos ([a-zA-Z0-9]+?) seguido de un espacio (), 10 veces ({0,10}), entonces la palabra 2 (bar).

Este no incluyen paradas completas (no sabía si querías), pero si desea agregar sólo después de .0-9 en la expresión regular.

Así que su (pseudocódigo) sintaxis será similares a:

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

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

Es de esperar que ayuda. Prueba a continuación, destacó lo que coincide.


ha trabajado:

El foo this that bar bla

El foo economic order war bar

no funcionó

El orden económico foo. barra de guerra

El orden mundial foo ha existido durante varios siglos, en este período de tiempo que las personas han desarrollado diferentes e intrincadas relaciones comerciales que tratan con situaciones como la agricultura y la barra

+0

Tal vez me falta algo, mi problema es que solo puedo cambiar toda la coincidencia de expresiones regulares (es decir, todas las palabras entre "foo" y "bar" también se modifican). No sé cómo tomar coincidencias y luego solo cambio las palabras "foo" y "bar" sin afectar ninguna otra palabra dentro del texto coincidente. Un problema secundario que es más un resultado de no tener un buen google-fu o la familiaridad con las macros de VBA es que no sé cómo cambiar el formato de una Regexp coincidente, solo cómo reemplazar el contenido. Actualicé mi pregunta con el macro en el que estoy trabajando actualmente. – pavja2

Cuestiones relacionadas