¿Cómo puedo obtener líneas donde una palabra específica se repite exactamente N veces?


8

Para esta entrada dada:

How to get This line that this word repeated 3 times in THIS line?
But not this line which is THIS word repeated 2 times.
And I will get This line with this here and This one
A test line with four this and This another THIS and last this

Quiero esta salida:

How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one

Obtener líneas enteras contiene solo tres palabras repetidas "esto". (coincidencia entre mayúsculas y minúsculas)


44
Para el votante demasiado amplio: ¿cómo puede una pregunta posiblemente volverse más específica?
— Jacob Vlijm el

@JacobVlijm En eso hay "demasiadas respuestas posibles". Elija $RANDOM_LANGUAGE: alguien podrá encontrar una solución.
— Muru

@muru Diría lo contrario, limitarlo a un idioma lo convertiría en una pregunta centrada en la programación (lenguaje). Ahora se trata de un problema en cuestión centrada. Quizás haya muchas soluciones posibles (idiomas), pero no tantas obvias.
— Jacob Vlijm

Respuestas:


13

En perl, reemplace thiscon mayúsculas y minúsculas y cuente el número de reemplazos:

$ perl -ne 's/(this)/$1/ig == 3 && print' <<EOF
How to get This line that this word repeated 3 times in THIS line?
But not this line which is THIS word repeated 2 times.
And I will get This line with this here and This one
A test line with four this and This another THIS and last this
EOF
How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one

Usando un recuento de coincidencias en su lugar:

perl -ne 'my $c = () = /this/ig; $c == 3 && print'

Si tienes GNU awk, una forma muy simple:

gawk -F'this' -v IGNORECASE=1 'NF == 4'

El número de campos será uno más que el número de separadores.


¿Por qué reemplazar? no podemos contarlo directamente sin reemplazar?
— αғsнιη

De hecho, podemos contar, el código es un poco más largo: stackoverflow.com/questions/9538542/…
— muru

Votación a favor del comando gawk.
— Sri

9

Asumiendo que su archivo fuente es tmp.txt,

grep -iv '.*this.*this.*this.*this' tmp.txt | grep -i '.*this.*this.*this.*'

El grep izquierdo genera todas las líneas que no tienen 4 o más ocurrencias de "this" que distinguen entre mayúsculas y minúsculas en tmp.txt.

El resultado se canaliza al grep derecho, que genera todas las líneas con 3 o más ocurrencias en el resultado grep izquierdo.

Actualización: Gracias a @Muru, aquí está la mejor versión de esta solución,

grep -Eiv '(.*this){4,}' tmp.txt | grep -Ei '(.*this){3}'

reemplace 4 con n + 1 y 3 con n.


Esto fallaría para N> 4. Y la primera grepnecesita terminar *.
— ps95

1
Quiero decir que no puedes escribir esto para N = 50. Y la pregunta es exactamente para tres, por lo que necesitas otro grep que descarte todas las salidas que contengan menos o igual que dos this. grep -iv '.*this.*this.*this.*this.*' tmp.txt | grep -i '.*this.*this.*this.* |grep -iv '.*this.*this.'
— ps95

@ prakharsingh95 No falló para n> 4 y * no se requiere en el primer grep.
— Sri

1
@KasiyA ¿Cuál es tu opinión sobre mi respuesta?
— Sri

55
Simplifíquelo un poco: grep -Eiv '(.*this){4,}' | grep -Ei '(.*this){3}'esto podría hacerlo práctico para N = 50.
— muru

9

En python, esto haría el trabajo:

#!/usr/bin/env python3

s = """How to get This line that this word repeated 3 times in THIS line?
But not this line which is THIS word repeated 2 times.
And I will get This line with this here and This one
A test line with four this and This another THIS and last this"""

for line in s.splitlines():
    if line.lower().count("this") == 3:
        print(line)

salidas:

How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one

O para leer desde un archivo, con el archivo como argumento:

#!/usr/bin/env python3
import sys

file = sys.argv[1]

with open(file) as src:
    lines = [line.strip() for line in src.readlines()]

for line in lines:
    if line.lower().count("this") == 3:
        print(line)
  • Pegue el script en un archivo vacío, guárdelo como find_3.py, ejecútelo con el comando:

    python3 /path/to/find_3.py <file_withlines>
    

Por supuesto, la palabra "this" se puede reemplazar por cualquier otra palabra (u otra cadena o sección de línea), y el número de ocurrencias por línea se puede establecer en cualquier otro valor en la línea:

    if line.lower().count("this") == 3:

Editar

Si el archivo fuera grande (cientos de miles / millones de líneas), el siguiente código sería más rápido; lee el archivo por línea en lugar de cargar el archivo a la vez:

#!/usr/bin/env python3
import sys
file = sys.argv[1]

with open(file) as src:
    for line in src:
        if line.lower().count("this") == 3:
            print(line.strip())

No soy un experto en python, ¿cómo puedo leer el archivo? gracias
— αғsнιη

1
@KasiyA editado para usar el archivo como argumento.
— Jacob Vlijm

Solo curiosidad: ¿por qué no usaste un generador en el segundo fragmento de código?
— Muru

6

Puedes jugar un poco con awkesto:

awk -F"this" 'BEGIN{IGNORECASE=1} NF==4' file

Esto devuelve:

How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one

Explicación

  • Lo que hacemos es definir el separador de campo para thissí mismo. De esta forma, la línea tendrá tantos campos +1 como veces thisaparezca la palabra .

  • Para hacerlo insensible a mayúsculas y minúsculas, utilizamos IGNORECASE = 1. Ver referencia: Sensibilidad a mayúsculas y minúsculas en el emparejamiento .

  • Entonces, es solo una cuestión de decir NF==4que todas esas líneas tengan thisexactamente tres veces. No se necesita más código, ya {print $0}que (es decir, imprimir la línea actual) es el comportamiento predeterminado de awkcuando una expresión se evalúa True.


Ya publicado , pero buena explicación.
— Muru

@muru ¡oh, no lo vi! Mis disculpas y +1 por ti.
— fedorqui

5

Suponiendo que las líneas se almacenan en un archivo llamado FILE:

while read line; do 
    if [ $(grep -oi "this" <<< "$line" | wc -w)  = 3 ]; then 
        echo "$line"; 
    fi  
done  <FILE

1
Gracias, puede eliminar su sed ...comando y agregar la -oopción para en su grep -oi ...lugar.
— αғsнιη

Más simple:$(grep -ic "this" <<<"$line")
— muru

2
@muru No, la -copción contará el número de líneas que coinciden con "este", no el número de "este" palabras en cada línea.
— αғsнιη

1
@KasiyA Ah, sí. Culpa mía.
— muru

@KasiyA, ¿no sería -ly -wsería equivalente en este caso?
— ps95

4

Si estás en Vim:

g/./if len(split(getline('.'), 'this\c', 1)) == 4 | print | endif

Esto solo imprimirá líneas coincidentes.


Un buen ejemplo para buscar líneas con n apariciones de palabras, cuando se usa Vim.
— Sri

0

Solución Ruby de una sola línea:

$ ruby -ne 'print $_ if $_.chomp.downcase.scan(/this/).count == 3' < input.txt                                    
How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one

Funciona de una manera bastante simple: redirigimos el archivo al stdin de ruby, ruby ​​obtiene la línea del stdin, lo limpia con chompy downcase, y scan().countnos da varias ocurrencias de una subcadena.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.