2
votes

Perl ou Awk: durée d'exécution du film Match supérieure à 5 heures

Je dois recataloguer tous les films dont la durée d'exécution est supérieure à 5 heures.

Exemple de données:

awk -F'\t' '$6 ~ /^.*\(.*[3-9][[:digit:]]{2}[[:space:]]+min.*\)/ {print}' minutes.csv

Existe-t-il un extrait de code perl ou awk rapide ou un- doublure qui: * Imprimez toute la ligne si * Le nombre de "min" est supérieur à 300 ou * Le nombre de "hr (s)" est supérieur à 5

Quelque chose comme:

perl -F\\t -ane 'print if $F[6] <substring or capture group representing minutes> > 300' file.csv

Rapprochez-vous avec awk :

239835<TAB> 92075<TAB>Moonlighting, seasons one and two<TAB>NVIDEO<TAB>DVD<TAB>6 videodiscs (approximately 1200 min.) :
628328  180001  7th heaven. NVIDEO  DVD 5 videodiscs (15 hr., 57 min.) :
773429  291072  Veronica Mars.  NVIDEO  DVD 6 videodiscs (842 min.) :
789908  379843  Castle in the Sky   NVIDEO  JDVD    2 videodiscs (approximately 125 min.) :
856287  208624  The Munsters.   NVIDEO  DVD 12 videodiscs (approximately 33 hr.) :
1076125 254085  From up on Poppy Hill (Rated PG)    NVIDEO  JDVD    2 videodiscs (91 min.) :
1154016 264851  Columbo.    NVIDEO  DVD 5 videodiscs (725 min.) :
1217001 113980  CSI, crime scene investigation. NVIDEO  DVD 5 videodiscs (approximately 732 min.) :
1227803 280535  Seattle Seahawks    NVIDEO  DVD 3 videodiscs (500 min.) :
1227804 280535  Seattle Seahawks    NVIDEO  DVD 3 videodiscs (500 min.) :
1287497 293511  Seattle Seahawks :  NVIDEO  DVD 3 videodiscs (400 min.) :
1287499 293511  Seattle Seahawks :  NVIDEO  DVD 3 videodiscs (400 min.) :
1367994 228775  Spongebob Squarepants.  NVIDEO  JDVD    4 videodiscs (469 min.) :
1368002 257248  SpongeBob SquarePants.  NVIDEO  JDVD    4 videodiscs (589 min.) :

Modèles REGEX: Minutes supérieures à 300: /^.*\(.*[[:space: ..............,.,..,.,.,.,.,. >

Minutes supérieures à 1 000: /^.*\(.*[[:digit:[/. 5: /^.*\(.*[[:space: ..............,.,.,......,.,.. > Heures supérieures à 10: /^.*\(.*[[:space: .

Existe-t-il un moyen plus simple et plus concis?


2 commentaires

Les données séparées par des tabulations ne fonctionnent pas bien avec SO. Où sont les colonnes séparées dans cet exemple?


Les ajoutera sur la première ligne pour que vous puissiez voir.


5 Réponses :


2
votes

Vous pouvez utiliser regex avec des groupes de capture avec perl:

> perl -ne'/\(.*?(?:(\d+) hr\.)?.*?(?:(\d+) min\.)?.*?\)/&&($1>5||$2>300)&&print' catalog
628328  180001  7th heaven. NVIDEO  DVD 5 videodiscs (15 hr., 57 min.) :
773429  291072  Veronica Mars.  NVIDEO  DVD 6 videodiscs (842 min.) :
1154016 264851  Columbo.    NVIDEO  DVD 5 videodiscs (725 min.) :
1227803 280535  Seattle Seahawks    NVIDEO  DVD 3 videodiscs (500 min.) :
1227804 280535  Seattle Seahawks    NVIDEO  DVD 3 videodiscs (500 min.) :
1287497 293511  Seattle Seahawks :  NVIDEO  DVD 3 videodiscs (400 min.) :
1287499 293511  Seattle Seahawks :  NVIDEO  DVD 3 videodiscs (400 min.) :
1367994 228775  Spongebob Squarepants.  NVIDEO  JDVD    4 videodiscs (469 min.) :
1368002 257248  SpongeBob SquarePants.  NVIDEO  JDVD    4 videodiscs (589 min.) :


3 commentaires

@bihsing Cela fonctionne! Auriez-vous la gentillesse de décomposer l ' regex pour moi? Je vois les groupes de capture indiqués par les parenthèses et j'obtiens la syntaxe . *? , mais qu'en est-il du ?: ?


Heureux d'avoir pu aider. (?: ...) est un groupe sans capture. Puisque nous voulons uniquement capturer les nombres, tous les autres groupes doivent être rendus non capturants. Les groupes non capturants ici sont utilisés pour regrouper l'ensemble du verbiage de xx h. ou yy min. ensemble afin que nous puissions utiliser le ? quantificateur pour les rendre facultatifs.


OP a souligné ailleurs que cette version n'imprime pas un certain nombre de lignes des données d'exemple qu'elle devrait, btw.



4
votes

Au lieu d'essayer de tout faire avec une seule expression régulière de monstre, je pense que la diviser en deux expressions différentes est plus lisible et plus facile à comprendre lorsque vous y reviendrez plus tard. Pas besoin d'alimenter le stéréotype de perl ressemblant à du bruit de ligne ...

$ perl -F\\t -ane 'print if ($F[5] =~ /(\d+) hr\./ && $1 > 5) || ($F[5] =~ /(\d+) min\./ && $1 > 300)' input.tsv

Ceci extrait les nombres avant h. ou min. dans la sixième colonne (et seulement celle-là au cas où une chaîne correspondante apparaît également dans la colonne nom) et les compare pour voir si elles sont supérieures à 5 ou 300 respectivement, et n'imprime que les lignes correspondantes.

p>


2 commentaires

Cette version semble plus précise, bien que je ne puisse pas dire pourquoi. L'autre réponse produit moins de résultats. Je me demande si l'expression se déclenche d'une manière ou d'une autre sur les faux positifs.


@Bubnoff Ouais, cette autre réponse perl ne capture pas correctement les nombres de beaucoup de chaînes. Dans la ligne Moonlighting, par exemple, tout ce qui se trouve entre les parenthèses a fini par correspondre au tout dernier . *? dans le RE avec tout le reste avant de correspondre à des sous-chaînes de longueur 0.



0
votes

Vous pouvez également utiliser awk:

> awk -F'[^0-9]+' '/min\./&&$(NF-1)>300||/hr\./&&$(NF-/min\./-1)>5' catalog
239835  92075   Moonlighting, seasons one and two   NVIDEO  DVD 6 videodiscs (approximately 1200 min.) :
628328  180001  7th heaven. NVIDEO  DVD 5 videodiscs (15 hr., 57 min.) :
773429  291072  Veronica Mars.  NVIDEO  DVD 6 videodiscs (842 min.) :
856287  208624  The Munsters.   NVIDEO  DVD 12 videodiscs (approximately 33 hr.) :
1154016 264851  Columbo.    NVIDEO  DVD 5 videodiscs (725 min.) :
1217001 113980  CSI, crime scene investigation. NVIDEO  DVD 5 videodiscs (approximately 732 min.) :
1227803 280535  Seattle Seahawks    NVIDEO  DVD 3 videodiscs (500 min.) :
1227804 280535  Seattle Seahawks    NVIDEO  DVD 3 videodiscs (500 min.) :
1287497 293511  Seattle Seahawks :  NVIDEO  DVD 3 videodiscs (400 min.) :
1287499 293511  Seattle Seahawks :  NVIDEO  DVD 3 videodiscs (400 min.) :
1367994 228775  Spongebob Squarepants.  NVIDEO  JDVD    4 videodiscs (469 min.) :
1368002 257248  SpongeBob SquarePants.  NVIDEO  JDVD    4 videodiscs (589 min.) :


0 commentaires

2
votes

Puisque 5 heures correspondent à 300 minutes, vous n'avez pas besoin de les traiter séparément, il suffit de convertir toutes les spécifications d'heures et / ou de minutes en minutes. En utilisant n'importe quel awk:

awk -F'\t' '
    {
        hrs  = ( match($6,/[0-9]+ hr/)  ? substr($6,RSTART)+0 : 0 )
        mins = ( match($6,/[0-9]+ min/) ? substr($6,RSTART)+0 : 0 )
    }
    (hrs > 5) || (mins > 300)
' file

mais vous pouvez l'écrire comme 2 tests séparés si vous préférez:

awk -F'\t' '
    {
        hrs  = ( match($6,/[0-9]+ hr/)  ? substr($6,RSTART)+0 : 0 )
        mins = ( match($6,/[0-9]+ min/) ? substr($6,RSTART)+0 : 0 )
    }
    (hrs*60 + mins) > 300
' file


6 commentaires

Comment écririez-vous cela avec GAWK moderne? Je n'ai pas pu faire fonctionner les groupes de capture avec match ($ 6, / REGEX /, a) ..etc. il ignorait les opérateurs de type {3,} .


Si je l'écrivais pour gawk, le seul changement que je ferais serait de tourner hrs = (match ($ 6, / [0-9] + hr /)? Substr ($ 6, RSTART) +0: 0 ) dans match ($ 6, / [0-9] + hr /, a); hrs = a [0] +0 et similaire pendant min. Je ne sais pas où vous pensez qu'un {3,} entrerait.


Vous avez raison, dans cet exemple particulier, {3,} ne serait pas utile. Dans mes tests, [avec des hypothèses erronées, comme vous le faites remarquer], cela n'a pas fonctionné et ma question est plus générale. Il s'agit d'une construction REGEX générique qui n'a pas fonctionné comme prévu dans la construction GAWK match ($ 6, / [0-9] {3,} hr /, a) . Je conviens que ce n'était pas nécessaire, mais je me demande pourquoi cela n'a pas fonctionné. Merci!


En quoi cela "n'a-t-il pas fonctionné"? Votre entrée ne contient aucune chaîne de 3 chiffres ou plus dans le 6ème champ - avez-vous pensé que c'est le cas et êtes-vous surpris quand gawk ne peut pas le trouver? Ou aviez-vous une entrée différente contre laquelle vous exécutez cela? Ou pensez-vous que [0-9] {3,} signifie autre chose que 3 chiffres ou plus ?


Dans certaines chaînes d'exécution, vous obtiendrez une chaîne comme celle-ci: 1250 min . Votre solution démontre que l'utilisation d'une construction telle que {3,} n'est cependant pas nécessaire, lorsqu'elle est utilisée sans la match construit la { 3,} fonctionne comme prévu - dans la construction match , il ne tire que les enregistrements avec 1 chiffre suivi de min. J'étais juste curieux de savoir si j'avais besoin d'évasion ... etc. Ce n'est pas grave et je ne veux pas prendre votre temps. Merci!


Vous êtes les bienvenus et ce n'est pas un problème. Non, vous n'avez pas besoin d'évasion. Je ne peux pas imaginer quel est le problème lorsque vous me l'avez dit jusqu'à présent, car pour tout outil qui gère les expressions rationnelles, soit {3,} signifie une répétition de 3 ou plus ou cela signifie littéralement la chaîne "{3,}" et aucun de ceux-ci ne correspondrait à 1 min ou similaire comme vous dites que vous voyez quand vous exécutez le code que vous courez contre n'importe quelle entrée contre laquelle vous l'exécutez. J'aurais donc besoin de voir un exemple concret. N'hésitez pas à publier une nouvelle question avec ses propres exemple minimal reproductible d'exemple d'entrée, de sortie attendue et de code si vous J'aimerais de l'aide.



0
votes

laissez vos données dans le fichier 'd',

perl -F"\(|\)" -ane '$t=@F[$#F-1]; $t =~ s/.*?(\d+\s*(?:min|hr.)).*/\1/; if($t =~ /min/ && $t>300 or $t =~ /hr./ && $t>5) {print "@F\n"}' d


0 commentaires