Con Perl, ¿cómo muestro el contexto alrededor de un término de búsqueda en los resultados de búsqueda?

StackOverflow https://stackoverflow.com/questions/616041

  •  03-07-2019
  •  | 
  •  

Pregunta

Estoy escribiendo una secuencia de comandos Perl que está buscando un término en grandes porciones de texto. Lo que me gustaría mostrarle al usuario es un pequeño subconjunto del texto alrededor del término de búsqueda, para que el usuario pueda tener un contexto del lugar donde se usa este término de búsqueda. Los resultados de búsqueda de Google son un buen ejemplo de lo que estoy tratando de lograr, donde el contexto de su término de búsqueda se muestra debajo del título del enlace.

Mi búsqueda básica es usar esto:

if ($text =~ /$search/i ) {
    print "${title}:${text}\n";
}

($ title contiene el título del elemento en el que se encontró el término de búsqueda) Sin embargo, esto es demasiado, ya que a veces $ text tendrá cientos de líneas de texto.

Esto se mostrará en la web, por lo que podría proporcionar el título como un enlace al texto real, pero no hay contexto para el usuario.

Intenté modificar mi expresión regular para capturar 4 palabras antes y 4 palabras después del término de búsqueda, pero tuve problemas si el término de búsqueda estaba al principio o al final de $ text.

¿Cuál sería una buena manera de lograr esto? Intenté buscar CPAN porque estoy seguro de que alguien tiene un módulo para esto, pero no puedo pensar en los términos correctos para buscar. Me gustaría hacer esto sin módulos si es posible, porque instalar los módulos aquí es un problema. ¿Alguien tiene alguna idea?

¿Fue útil?

Solución

Tu intento inicial de 4 palabras antes / después no estaba muy lejos.

Prueba:

if ($text =~ /((\S+\s+){0,4})($search)((\s+\S+){0,4})/i) {
    my ($pre, $match, $post) = ($1, $3, $4);
    ...
}

Otros consejos

Puede usar $ y $ 'para obtener la cadena antes y después de la coincidencia. Luego trunca esos valores apropiadamente. Pero como señala blixtor, shlomif tiene razón al sugerir el uso de @ + y @ - para evitar la penalización de rendimiento impuesta por $ y # '-

$foo =~ /(match)/;

my $match = $1;
#my $before = 

Puede usar $ y $ 'para obtener la cadena antes y después de la coincidencia. Luego trunca esos valores apropiadamente. Pero como señala blixtor, shlomif tiene razón al sugerir el uso de @ + y @ - para evitar la penalización de rendimiento impuesta por $ y # '-

; #my $after = ; my $before = substr($foo, 0, $-[0]); my $after = substr($foo, <*>[0]); $after =~ s/((?:(?:\w+)(?:\W+)){4}).*/$1/; $before = reverse $before; # reverse the string to limit backtracking. $before =~ s/((?:(?:\W+)(?:\w+)){4}).*/$1/; $before = reverse $before; print "$before -> $match <- $after\n";

Sugeriría usar los parámetros posicionales - @ + y @ - (ver perldoc perlvar) para encontrar la posición en la cadena de la coincidencia, y cuánto cuesta.

Puede intentar lo siguiente:

if ($text =~ /(.*)$search(.*)/i ) {

  my @before_words = split ' ', $1;
  my @after_words = split ' ',$2;

  my $before_str = get_last_x_words_from_array(@before_words);
  my $after_str = get_first_x_words_from_array(@after_words); 

  print $before_str . ' ' . $search . ' ' . $after_str;

}

Algún código obviamente se omite, pero esto debería darle una idea del enfoque.

En cuanto a extraer el título ... Creo que este enfoque no se presta muy bien a eso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top