文章(a / an / the)和数字(1-4位)之间的RegEx短语

时间:2013-04-01 23:03:38

标签: regex bash sed awk grep

我已经尝试了几十种正则表达式的排列来解决这个问题,但我没有遇到任何运气。

我需要遍历几十个文件,在“a / a / an”和1-4中可能的数字之间拉出特定的短语,忽略标点符号,例如{}()[]。

实施例

  

快速的棕色狐狸{15}以某种方式跳过懒狗[20] 4   这绝对不适合所有观众(0012)。

应该返回:

  快速的棕色狐狸15

     懒狗20

     某种方式4

     

观众0012

消除标点符号不是问题:sed 's/[][{}()]//g'

有什么建议吗?

4 个答案:

答案 0 :(得分:1)

在GNU awk中,您可以将输入拆分为以数字结尾的记录,这些数字可选择用标点符号包围:

$ cat file
The quick brown fox {15} jumps over the lazy dog [20] in a certain way 4 that is definitely not appropriate for all of the viewers (0012).


$ gawk -v RS='[[:punct:]]*[[:digit:]]+[[:punct:]]*' 'RT{print $0 RT}' file
The quick brown fox {15}
 jumps over the lazy dog [20]
 in a certain way 4
 that is definitely not appropriate for all of the viewers (0012).

然后你需要做的就是打印你想要的记录部分和记录终结者:

$ gawk -v RS='[[:punct:]]*[[:digit:]]+[[:punct:]]*' 'RT{print gensub(/.*\y(the|a|an)\y/,"\\1","") gensub(/[[:punct:]]/,"","g",RT)}' file
The quick brown fox 15
the lazy dog 20
a certain way 4
the viewers 0012

我刚刚注意到,在您的示例中,您将输出转换为全部小写。只需在打印之前抛出$0=tolower($0)即可(也解决了使the|a|an比较不区分大小写的问题):

$ gawk -v RS='[[:punct:]]*[[:digit:]]+[[:punct:]]*' 'RT{$0=tolower($0); print gensub(/.*\y(the|a|an)\y/,"\\1","") gensub(/[[:punct:]]/,"","g",RT)}' file

答案 1 :(得分:1)

Pure Bash和使用正则表达式的练习:

while read line ; do
  line=" $line"                                 # add leading space as word boundary

  while [ -n "$line" ] ; do
    [[ "$line" =~ [[:space:]]((an|a|the|An|A|The)([[:space:]]+[^[:digit:]]+)([[:digit:]]{1,4}))(.+$) ]]

    match="${BASH_REMATCH[2]}${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
    match=${match//[()\[\]\{\}]/}               # remove parentheses
    [ -n "$match" ] && echo "'$match'"          # print if not empty

    line="${BASH_REMATCH[5]}"                   # the postmatch
  done
done < "$infile"

输出:

'The quick brown fox 15'
'the lazy dog 20'
'a certain way 4'
'the viewers 0012'

答案 2 :(得分:0)

grep -ioP "(a|an|the).*?\d{1,4}" files

-o将仅打印匹配的文本,并且每个匹配都在其自己的行上。 -P用于不情愿的量词,也可以自动扩展正则表达式。您当然可以按照上面的建议将此输出传输到sed

答案 3 :(得分:0)

这可能适合你(GNU sed):

sed -r '/\b(the|an|a)\b/I!d;s//\n&/;s/[^\n]*\n//;s/\{([0-9]{1,4})\}|\(([0-9]{1,4})\)|\[([0-9]{1,4})\]|\b([0-9]{1,4})\b/\1\2\3\4\n/;P;D' file