regex - probar - Expresión regular reemplazar una palabra por un enlace
regex replace online (7)
Quiero escribir una expresión regular que reemplace la palabra París por un enlace, ya que solo la palabra no está lista como parte de un enlace.
Ejemplo:
i''m living <a href="Paris" atl="Paris link">in Paris</a>, near Paris <a href="gare">Gare du Nord</a>, i love Paris.
se convertiría
i''m living.........near <a href="">Paris</a>..........i love <a href="">Paris</a>.
Respuesta tradicional para dicha pregunta: use un analizador de HTML real. Porque las RE no son realmente buenas para operar en un contexto. Y HTML es complejo, una etiqueta ''a'' puede tener atributos o no, en cualquier orden, puede tener HTML en el enlace o no, etc.
Si no estaba limitado a usar expresiones regulares en este caso, XSLT es una buena opción para un idioma en el que puede definir este reemplazo, porque ''entiende'' XML.
Usted define dos plantillas: una plantilla encuentra enlaces y elimina los enlaces que no tienen "París" como el texto del cuerpo. Otra plantilla encuentra todo lo demás, la divide en palabras y agrega etiquetas.
Expresión regular:
!(<a.*</a>.*)*Paris!isU
Reemplazo:
$1<a href="Paris">Paris</a>
$ 1 de referencia al primer subpatrón (al menos en PHP). Dependiendo del idioma que use, podría ser un poco diferente.
Esto debería reemplazar todas las ocurrencias de "París" con el enlace en el reemplazo. Solo comprueba si todas las A-Tags de apertura se cerraron antes de "París".
Ejemplo de PHP:
<?php
$s = ''i/'m living <a href="Paris" atl="Paris link">in Paris</a>, near Paris <a href="gare">Gare du Nord</a>, i love Paris.'';
$regex = ''!(<a.*</a>.*)*Paris!isU'';
$replace = ''$1<a href="Paris">Paris</a>'';
$result = preg_replace( $regex, $replace, $s);
?>
Adición:
Esta no es la mejor solución. Una situación en la que esta expresión regular no funcionará es cuando tienes una etiqueta-img, que no está dentro de un elemento-a. Cuando establezca el atributo de título de esa imagen en "París", este "París" también será reemplazado. Y eso no es lo que quieres. Sin embargo, no veo ninguna manera de resolver tu problema completamente con una simple expresión regular.
Regexes no reemplazan. Los idiomas lo hacen
Los idiomas y las bibliotecas también leen de la base de datos o archivo que contiene la lista de palabras que le interesan y asocian una URL con su nombre. Aquí está la sustitución más fácil que puedo imaginar, mi única expresión regular (se usa Perl para la sintaxis de reemplazo ).
s/([a-z-'']+)/<a href="http:////en.wikipedia.org//wiki//$1">$1<//a>/i
Los nombres correctos pueden funcionar mejor:
s/([A-Z][a-z-'']+)/<a href="http:////en.wikipedia.org//wiki//$1">$1<//a>/gi;
Por supuesto, "Baton Rouge" se convertiría en dos enlaces para:
<a href="http://en.wikipedia.org/wiki/Baton">Baton</a>
<a href="http://en.wikipedia.org/wiki/Rouge">Rouge</a>
En Perl , puedes hacer esto:
my $barred_list_of_cities
= join( ''|''
, sort { ( length $a <=> $b ) || ( $a cmp $b ) } keys %url_for_city_of
);
s/($barred_list_of_cities)/<a href="$url_for_city_of{$1}">$1<//a>/g;
Pero, de nuevo, es un lenguaje que implementa un conjunto de operaciones para expresiones regulares, las expresiones regulares no hacen nada. (En realidad, es una aplicación tan común, que me sorprendería que no haya un módulo CPAN por ahí que haga esto, y solo tiene que cargar el hash.
Puede buscar esta expresión regular:
(<a[^>]*>.*?</a>)|Paris
Esta expresión regular coincide con un enlace, que captura en el primer (y único) grupo de captura, o la palabra París.
Reemplace la coincidencia con su enlace solo si el grupo de captura no coincide con nada.
Por ejemplo, en C #:
resultString =
Regex.Replace(
subjectString,
"(<a[^>]*>.*?</a>)|Paris",
new MatchEvaluator(ComputeReplacement));
public String ComputeReplacement(Match m) {
if (m.groups(1).Success) {
return m.groups(1).Value;
} else {
return "<a href=/"link to paris/">Paris</a>";
}
}
$pattern = ''Paris'';
$text = ''i/'m living <a href="Paris" atl="Paris link">in Paris</a>, near Paris <a href="gare">Gare du Nord</a>, i love Paris.'';
// 1. Define 2 arrays:
// $matches[1] - array of links with our keyword
// $matches[2] - array of keyword
preg_match_all(''@(<a[^>]*?>[^<]*?''.$pattern.''[^<]*?</a>)|(?<!/pL)(''.$pattern.'')(?!/pL)@'', $text, $matches);
// Exists keywords for replace? Define first keyword without tag <a>
$number = array_search($pattern, $matches[2]);
// Keyword exists, let''s go rock
if ($number !== FALSE) {
// Replace all link with temporary value
foreach ($matches[1] as $k => $tag) {
$text = preg_replace(''@(<a[^>]*?>[^<]*?''.$pattern.''[^<]*?</a>)@'', ''KEYWORD_IS_ALREADY_LINK_''.$k, $text, 1);
}
// Replace our keywords with link
$text = preg_replace(''/(?<!/pL)(''.$pattern.'')(?!/pL)/'', ''<a href="">''.$pattern.''</a>'', $text);
// Return link
foreach ($matches[1] as $k => $tag) {
$text = str_replace(''KEYWORD_IS_ALREADY_LINK_''.$k, $tag, $text);
}
// It''s work!
echo $text;
}
Esto es difícil de hacer en un solo paso. Escribir una expresión regular única que hace eso es prácticamente imposible.
Pruebe un enfoque de dos pasos.
- Ponga un enlace alrededor de cada "París" que hay, independientemente de si ya hay otro enlace presente.
- Encuentre todos los enlaces anidados incorrectamente (
<a href="..."><a href="...">Paris</a></a>
) y elimine el enlace interno.
Regex para el primer paso es muy simple:
/bParis/b
Regex para el paso dos es un poco más complejo:
(<a[^>]+>.*?(?!:</a>))<a[^>]+>(Paris)</a>
Usa esa en toda la cadena y reemplázala con el contenido de los grupos 1 y 2, eliminando de manera efectiva el enlace interno excedente.
Explicación de regex # 2 en palabras simples:
- Encuentre todos los enlaces (
<a[^>]+>
), opcionalmente seguidos por cualquier cosa que no sea seguida de un enlace de cierre (.*?(?!:</a>)
). Guárdelo en el grupo de coincidencia 1. - Ahora busca el siguiente enlace (
<a[^>]+>
). Asegúrate de que esté allí, pero no lo guardes. - Ahora busca la palabra Paris. Guárdalo en el grupo de partidos 2.
- Busque un enlace de cierre (
</a>
). Asegúrate de que esté allí, pero no lo guardes. - Reemplace todo con el contenido de los grupos 1 y 2, perdiendo así todo lo que no guardó.
El enfoque asume estas condiciones secundarias:
- Su HTML de entrada no está horriblemente roto.
- Su sabor regex admite cuantificadores no codiciosos (. *?) Y aserciones negativas de prelación de ancho cero (
(?!:...)
). - Envuelve la palabra "Paris" solo en un enlace en el paso 1, sin caracteres adicionales. Cada "
Paris
" se convierte en "<a href"...">Paris</a>
", o el paso dos fallará (hasta que cambie la segunda expresión regular). Por cierto: regex # 2 explícitamente permite construcciones como esta:
<a href="">in the <b>capital of France</b>, <a href="">Paris</a></a>
El enlace excedente proviene del paso uno, el resultado de reemplazo del paso 2 será:
<a href="">in the <b>capital of France</b>, Paris</a>