我已经尝试了几十种正则表达式的排列来解决这个问题,但我没有遇到任何运气。
我需要遍历几十个文件,在“a / a / an”和1-4中可能的数字之间拉出特定的短语,忽略标点符号,例如{}()[]。
实施例
快速的棕色狐狸{15}以某种方式跳过懒狗[20] 4 这绝对不适合所有观众(0012)。
应该返回:
快速的棕色狐狸15 懒狗20 某种方式4观众0012
消除标点符号不是问题:sed 's/[][{}()]//g'
有什么建议吗?
答案 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