【问题标题】:Perl or Awk: Match Movie run times greater than 5 hoursPerl 或 Awk:匹配电影运行时间大于 5 小时
【发布时间】:2019-04-12 15:18:50
【问题描述】:

我需要重新编目所有运行时间超过 5 小时的电影。

样本数据:

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.) :

是否有一个快速的 perl 或 awk sn-p 或 one-liner 可以: * 如果打印整行 * # of "min" 大于 300 或 * # of "hr(s)" 大于 5

类似:

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

awk更亲密:

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

正则表达式模式: 超过 300 分钟: /^.*\(.*[[:space:]][3-9][[:digit:]]{2}[[:space:]]+min.*\)/

分钟数大于 1000: /^.*\(.*[[:digit:]]{4,}[[:space:]]+min.*\)/

小时数大于 5: /^.*\(.*[[:space:]][5-9]{1}[[:space:]]+hr.*\)/

大于 10 小时: /^.*\(.*[[:space:]][[:digit:]]{4}[[:space:]]+hr.*\)/

有没有更简单更简洁的方法?

【问题讨论】:

  • 制表符分隔的数据不能很好地与 SO 配合使用。该示例中的列在哪里分开?
  • 将它们添加到第一行,以便您查看。

标签: regex perl awk


【解决方案1】:

与其尝试使用一个怪物正则表达式来完成所有工作,我认为将它分成几个不同的表达式更易读,当您稍后再看它时更容易理解。无需提供看起来像线路噪音的 perl 刻板印象......

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

这会提取第六列中hr.min. 之前的数字(如果匹配的字符串也出现在名称列中,则只提取那个数字)并比较它们以查看它们是否大于 5 或​​ 300分别,并且只打印那些匹配的行。

【讨论】:

  • 这个版本似乎更准确,虽然我说不出为什么。另一个答案产生的结果较少。我想知道这个表达式是否以某种方式被误报绊倒了。
  • @Bubnoff 是的,其他 perl 答案没有正确捕获大量字符串中的数字。例如,在 Moonlighting 行中,括号之间的所有内容最终匹配 RE 中最后一个 .*? 与匹配 0 长度子字符串之前的所有其他内容。
【解决方案2】:

您可以通过 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.) :

【讨论】:

  • @bihsing 这行得通!你能帮我分解一下regex吗?我看到括号表示的捕获组,我得到了 .*? 语法,但是 ?: 呢?
  • 很高兴能提供帮助。 (?:...) 是非捕获组。由于我们只想捕获数字,因此应将所有其他组设为非捕获。这里的非捕获组用于将xx hr.yy min. 的整个词组组合在一起,以便我们可以使用? 量词使它们都成为可选的。
  • OP 在其他地方指出,这个版本没有打印它应该打印的样本数据行数,顺便说一句。
【解决方案3】:

由于 5 小时是 300 分钟,因此您无需单独处理它们,只需将任何小时和/或分钟规范转换为分钟即可。使用任何 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*60 + mins) > 300
' file

但如果您愿意,可以将其编写为 2 个单独的测试:

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

【讨论】:

  • 你会如何用现代 GAWK 写这个?我无法让捕获组使用match($6, /REGEX/ , a) ..etc。它忽略了{3,} 类型运算符。
  • 如果我是为 gawk 编写的,我唯一要做的改变就是将 hrs = ( match($6,/[0-9]+ hr/) ? substr($6,RSTART)+0 : 0 ) 变成 match($6,/[0-9]+ hr/,a); hrs=a[0]+0 并在几分钟内类似。我不知道你认为{3,} 会出现在哪里。
  • 你是对的,在这个特定的例子中{3,} 不会有用。在我的测试中,[假设错误,正如您指出的那样],它不起作用,我的问题更笼统。这是一个通用的 REGEX 构造,在 GAWK match($6,/[0-9]{3,} hr/,a) 构造中没有按预期工作。我同意这是不必要的,但我想知道为什么它不起作用。谢谢!
  • 它以什么方式“不起作用”?您的输入在第 6 个字段中不包含任何 3 位或更多位的字符串 - 您是否认为它包含并且当 gawk 找不到它时感到惊讶?或者您是否有一些不同的输入要针对它运行?或者你认为[0-9]{3,} 的意思不是3 or more digits
  • 不客气,没问题。不,你不需要逃脱。我无法想象到目前为止你告诉我的问题是什么,因为除了处理正则表达式之外的任何工具{3,} 意味着a repetition of 3 or more 或者它的字面意思是the string "{3,}" 并且它们都不匹配1 min 或类似于您所说的,当您针对您正在运行的任何输入运行您正在运行的任何代码时,您会看到。所以我需要看一个具体的例子。如果您需要帮助,请随时使用它自己的minimal reproducible example 示例输入、预期输出和代码发布一个新问题。
【解决方案4】:

你也可以使用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.) :

【讨论】:

    【解决方案5】:

    让你的数据在'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
    

    【讨论】:

      猜你喜欢
      • 2017-10-18
      • 2011-08-04
      • 1970-01-01
      • 2014-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多