Agrego esta respuesta como información relacionada a expresiones regulares. Es mi primer respuesta en SO en Español y no es una traducción, por lo que si no está correcta puedo eliminarla o corregirla.
Con respecto a lo que comentaste en tu pregunta:
(?! ) -> conocido como Negated lookahead en inglés
[^\w] -> conocido como Character class en inglés (en este caso negada)
Esto son dos conceptos diferentes. Por un lado tenés lo que se considera un lookaround
y por otro lado una character class. Funcionan de este modo:
Lookarounds
Los lookaround, se podria entender como diferentes formas de ver si un patrón está (o no está) precedido o sucedido por otro patrón. Por ejemplo, la expresión hola(?!chau)
va a hacer matching de la palabra hola
siempre y cuando no exista la palabra chau
a continuación.
Es decir:
hola, ¿qué tal? <-- OK
hola SO <-- OK
holachau <-- Falla
Tu pregunta esta relacionada sobre "cómo negar", pero también quería mencionarte que los lookarounds se dividen en:
- Lookahead (ver hacia adelante):
- Positive: se define como
hola(?=chau)
y va a matchear la palabra hola solo si a continuacion existe chau
- Negative: se define como
hola(?!chau)
y va a matchear la palabra hola solo si a continuacion NO existe chau
- Lookbehind (ver hacia atras):
- Positive: se define como
(?<=chau)hola
y va a matchear la palabra hola solo si a existe chau antes que hola
- Negative: se define como
(?<!chau)hola
y va a matchear la palabra hola solo si NO existe chau antes que hola
Es importante mencionar que los lookbehind no están soportados por Javascript en todos los navegadores (ver compatibilidad).
Podes encontrar mas informacion sobre los lookarounds en:
http://www.regular-expressions.info/lookaround.html
Character classes (Clases de caracteres)
Por otro lado, existen los character class, que en español una forma de entenderlo sería como conjunto de caracteres (o clase de caracteres) y se usa usando los corchetes [
..]
.
Es decir, que si tenemos [aeiou]
, solo se va a hacer matching con las vocales sin tildes.
Del mismo modo, una clase se puede negar, como mencionaste usando ^
al principio... por lo que [^aeiou]
en este caso va a hacer matching con un caracter que no sea una vocal sin tilde.
Aca hay mas informacion de los character classes:
http://www.regular-expressions.info/charclass.html
Verbos
Ahora, luego de darte un poco de contexto. Si querés usar expresiones regulares para tomar/coincidir todas las palabras que no estén entre comillas, entonces PCRE (Expresiones Regulares Compatibles con Perl, soportadas por PHP, R, Delphi y otros) tiene verbos que son muy útiles en tu caso.
Los más conocidos son (*SKIP)
y (*FAIL)
que se suelen usar en conjunto y se suelen usar de esta forma:
".*?"(*SKIP)(*FAIL)|(\w+)
Ejemplo practico
Este tipo de patrones se suele llamar técnica de descarte (discard technique), y siempre usan la misma forma de patrones separado por OR
:
patrón de descarte 1|patrón de descarte 2|patrón de descarte N|(GUARDAR ESTO)
Por ende, la expresión de arriba ".*?"(*SKIP)(*FAIL)|(\w+)
va a descartar todas las coincidencias de lo que esté antes de skip y fail (".*?"
), y se va a capturar el ultimo patrón (que está usando paréntesis... los paréntesis se usan para capturar contenido).
La expresión regular ".*?"(*SKIP)(*FAIL)|(\w+)
explicada sería:
".*?" Lo uso para buscar lo que SI quiero descartar, y para indicarle
al engine que descarte agrego (*SKIP)(*FAIL)
|(\w+) o (si el patrón no se descarta) busco las palabras y las capturo
Por ende, en el link de arriba, cuando se aplica esa expresión al texto:
Lorem ipsum "dolor sit amet", consectetur adipiscing elit, maecenas est felis "sit amet".
Se captura el siguiente contenido:
MATCH 1
1. [0-5] `Lorem`
MATCH 2
1. [6-11] `ipsum`
MATCH 3
1. [30-41] `consectetur`
MATCH 4
1. [42-52] `adipiscing`
MATCH 5
1. [53-57] `elit`
MATCH 6
1. [59-67] `maecenas`
MATCH 7
1. [68-71] `est`
MATCH 8
1. [72-77] `felis`
Conclusión, las expresiones regulares en mi opinión son espectaculares pero sólo si se saben usar. En mi caso personal, no puedo vivir sin ellas, pero como todo... para clavar un clavo se necesita un martillo y no un destornillador. En el caso de las regex, son excelentes para pattern matching, pero si necesitás lógica entonces definitivamente no es la herramienta indicada.