Imprimer le mot contenant la chaîne et le premier mot

10

Je veux trouver une chaîne dans une ligne de texte et imprimer la chaîne (entre les espaces) et le premier mot de la phrase.

Par exemple:

"Ceci est une seule ligne de texte"
"Autre chose"
"Il vaut mieux réessayer"
"Mieux"

La liste des chaînes est:

texte
chose
essayer
Mieux

Ce que j'essaie, c'est d'obtenir une table comme celle-ci:

Ce texte [tab]
Une autre chose [tab]
Il [tab] essaie
Mieux

J'ai essayé avec grep mais rien ne s'est produit. Toute suggestion?

Felipe Lira
la source
Donc, essentiellement "Si la ligne a une chaîne, imprimez le premier mot + la chaîne". Droite ?
Sergiy Kolodyazhnyy

Réponses:

12

Version 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

Appelez-le ainsi:

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

Production:

This    text
Another thing
It  try
Better
wjandrea
la source
9

Perl à la rescousse!

#!/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";
    }
}

Enregistrer sous first-plus-word, exécuter sous

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

Il crée une expression régulière à partir des mots d'entrée. Chaque ligne est ensuite comparée à l'expression rationnelle, et s'il y a correspondance, le premier mot est imprimé et s'il est différent du mot, le mot est également imprimé.

choroba
la source
9

Voici une version 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

file2est la liste de mots et file1contient les phrases.

tournevis
la source
2
Bon! Je l'ai mis dans un fichier de script, paste.ubuntu.com/23063130 , juste pour plus de commodité
Sergiy Kolodyazhnyy
8

Voici la version 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("")

Démo:

$> 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

Note latérale : le script est python3compatible, vous pouvez donc l'exécuter avec python2ou python3.

Sergiy Kolodyazhnyy
la source
7

Essaye ça:

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

Si l'onglet avant le Betterest un problème, essayez ceci:

$ 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

Ce qui précède a été testé sur GNU sed (appelé gsedsur OSX). Pour BSD sed, quelques modifications mineures peuvent être nécessaires.

Comment ça fonctionne

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

    Cela recherche un mot, [[:alnum:]]+suivi d'un espace, [[:space:]]suivi de n'importe quoi .*, suivi d'un de vos mots text|thing|try|Better, suivi de n'importe quoi. S'il est trouvé, il est remplacé par le premier mot de la ligne (le cas échéant), un onglet et le mot correspondant.

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

    Si la commande de substitution a entraîné une substitution, ce qui signifie qu'un de vos mots a été trouvé sur la ligne, la tacommande indique à sed de passer à l'étiquette a. Sinon, nous branchons ( b) à la ligne suivante. :adéfinit l'étiquette a. Donc, si l'un de vos mots a été trouvé, nous (a) faisons la substitution s/^\t//qui supprime un onglet de tête s'il y en a un, et (b) imprimons ( p) la ligne.

John1024
la source
7

Une approche bash / sed simple:

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

Le while read w; do ...; done < wordsva parcourir chaque ligne du fichier wordset l'enregistrer sous $w. La -nmarque sedn'imprime rien par défaut. La sedcommande remplacera ensuite les guillemets doubles suivis par des espaces non blancs ( \"(\S*), les parenthèses servent à "capturer" ce qui correspond \S*, le premier mot, et nous pourrons plus tard l'appeler \1), 0 ou plusieurs caractères ( .*), puis le mot que nous recherchons ( $w) et 0 ou plusieurs caractères à nouveau ( .*). Si cela correspond, nous le remplaçons par seulement le 1er mot, un onglet et $w( \1\t$w), et imprimons la ligne (c'est ce que fait le pin s///p).

terdon
la source
5

Ceci est la version 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

L'exemple de fichier texte hello.txtcontient

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

Exécution avec des ruby source.rb hello.txtrésultats dans

This    text
Another thing
It      try
Better
Anwar
la source