Imprimir palabra que contiene cadena y primera palabra

10

Quiero encontrar una cadena en una línea de texto e imprimir la cadena (entre espacios) y la primera palabra de la frase.

Por ejemplo:

"Esta es una sola línea de texto"
"Otra cosa"
"Es mejor que lo intentes de nuevo"
"Mejor"

La lista de cadenas es:

texto
cosa
tratar
Mejor

Lo que intento es obtener una tabla como esta:

Este texto [tab]
Otra cosa [tab]
[Tab] intente
Mejor

Lo intenté con grep pero no ocurrió nada. ¿Cualquier sugerencia?

Felipe Lira
fuente
Entonces, básicamente "Si la línea tiene cadena, imprime la primera palabra + cadena". Derecho ?
Sergiy Kolodyazhnyy

Respuestas:

12

Versión bash / grep:

#!/bin/bash
# string-and-first-word.sh
# Finds a string and the first word of the line that contains that string.

text_file="$1"
shift

for string; do
    # Find string in file. Process output one line at a time.
    grep "$string" "$text_file" | 
        while read -r line
    do
        # Get the first word of the line.
        first_word="${line%% *}"
        # Remove special characters from the first word.
        first_word="${first_word//[^[:alnum:]]/}"

        # If the first word is the same as the string, don't print it twice.
        if [[ "$string" != "$first_word" ]]; then
            echo -ne "$first_word\t"
        fi

        echo "$string"
    done
done

Llámalo así:

./string-and-first-word.sh /path/to/file text thing try Better

Salida:

This    text
Another thing
It  try
Better
wjandrea
fuente
9

¡Perl al rescate!

#!/usr/bin/perl
use warnings;
use strict;

my $file = shift;
my $regex = join '|', map quotemeta, @ARGV;
$regex = qr/\b($regex)\b/;

open my $IN, '<', $file or die "$file: $!";
while (<$IN>) {
    if (my ($match) = /$regex/) {
        print my ($first) = /^\S+/g;
        if ($match ne $first) {
            print "\t$match";
        }
        print "\n";
    }
}

Guardar como first-plus-word, correr como

perl first-plus-word file.txt text thing try Better

Crea una expresión regular de las palabras de entrada. Cada línea se compara con la expresión regular, y si hay una coincidencia, se imprime la primera palabra, y si es diferente a la palabra, la palabra también se imprime.

choroba
fuente
9

Aquí hay una versión awk:

awk '
  NR==FNR {a[$0]++; next;} 
  {
    gsub(/"/,"",$0);
    for (i=1; i<=NF; i++)
      if ($i in a) printf "%s\n", i==1? $i : $1"\t"$i;
  }
  ' file2 file1

donde file2está la lista de palabras y file1contiene las frases.

conductor de acero
fuente
2
Bueno uno! Lo puse en un archivo de script, paste.ubuntu.com/23063130 , solo por conveniencia
Sergiy Kolodyazhnyy
8

Aquí está la versión de Python:

#!/usr/bin/env python
from __future__ import print_function 
import sys

# List of strings that you want
# to search in the file. Change it
# as you fit necessary. Remember commas
strings = [
          'text', 'thing',
          'try', 'Better'
          ]


with open(sys.argv[1]) as input_file:
    for line in input_file:
        for string in strings:
            if string in line:
               words = line.strip().split()
               print(words[0],end="")
               if len(words) > 1:
                   print("\t",string)
               else:
                   print("")

Manifestación:

$> cat input_file.txt                                                          
This is a single text line
Another thing
It is better you try again
Better
$> python ./initial_word.py input_file.txt                                      
This    text
Another     thing
It  try
Better

Nota al margen : el script es python3compatible, por lo que puede ejecutarlo con python2o python3.

Sergiy Kolodyazhnyy
fuente
7

Prueba esto:

$ sed -En 's/(([[:alnum:]]+)[[:space:]].*)?(text|thing|try|Better).*/\2\t\3/p' File
This    text
Another thing
It      try
        Better

Si la pestaña anterior Betteres un problema, intente esto:

$ sed -En 's/(([[:alnum:]]+)[[:space:]].*)?(text|thing|try|Better).*/\2\t\3/; ta; b; :a; s/^\t//; p' File
This    text
Another thing
It      try
Better

Lo anterior se probó en GNU sed (llamado gseden OSX). Para BSD sed, pueden ser necesarios algunos cambios menores.

Cómo funciona

  • s/(([[:alnum:]]+)[[:space:]].*)?(text|thing|try|Better).*/\2\t\3/

    Esto busca una palabra, [[:alnum:]]+seguida de un espacio, [[:space:]]seguida de cualquier cosa .*, seguida de una de sus palabras text|thing|try|Better, seguida de cualquier cosa. Si se encuentra eso, se reemplaza con la primera palabra en la línea (si existe), una pestaña y la palabra coincidente.

  • ta; b; :a; s/^\t//; p

    Si el comando de sustitución resultó en una sustitución, lo que significa que una de sus palabras se encontró en la línea, entonces el tacomando le dice a sed que salte a la etiqueta a. Si no, entonces ramificamos ( b) a la siguiente línea. :adefine la etiqueta a. Entonces, si se encontró una de sus palabras, nosotros (a) hacemos la sustitución s/^\t//que elimina una pestaña inicial si hay una, y (b) imprimimos ( p) la línea.

John1024
fuente
7

Un enfoque simple bash / sed:

$ while read w; do sed -nE "s/\"(\S*).*$w.*/\1\t$w/p" file; done < words 
This    text
Another thing
It  try
    Better

El while read w; do ...; done < wordsiterará sobre cada línea en el archivo wordsy lo guardará como $w. Las -nmarcas sedno imprimen nada por defecto. El sedcomando a continuación, reemplazará a las comillas dobles seguidos de no está en blanco ( \"(\S*)los paréntesis sirven para "capturar" lo que se corresponde con \S*la primera palabra, y después nos pueden referirse a ella como \1), 0 o más caracteres ( .*) y luego el palabra que estamos buscando ( $w) y 0 o más caracteres nuevamente ( .*). Si esto coincide, lo reemplazamos con solo la primera palabra, una pestaña y $w( \1\t$w), e imprimimos la línea (eso es lo que hace el pin s///p).

terdon
fuente
5

Esta es la versión Ruby

str_list = ['text', 'thing', 'try', 'Better']

File.open(ARGV[0]) do |f|
  lines = f.readlines
  lines.each_with_index do |l, idx|
    if l.match(str_list[idx])
      l = l.split(' ')
      if l.length == 1
        puts l[0]
      else
        puts l[0] + "\t" + str_list[idx]
      end
    end
  end
end

El archivo de texto de muestra hello.txtcontiene

This is a single text line
Another thing
It is better you try again
Better

Ejecutando con ruby source.rb hello.txtresultados en

This    text
Another thing
It      try
Better
Anwar
fuente