我有一个包含多列的文件,各列之间用下划线 (_) 分隔。
大多数列的第一个字符以大写字母开头,有些以小写字母开头。
我打算提取每一行的字符串,该字符串以大写字母开头,下一列以小写字母开头。每一条线都会至少发生一次这样的情况。(更新:如果只有第一场比赛就太好了)。棘手的部分是这种情况不会发生在每一行的同一列。
例如:
Today_is_a_Good_Day
It_Doesnt_rain
i_dont_Like_rainy_day
期望的输出:
Today_is
Doesnt_rain
Like_rainy
有没有办法使用 grep/sed/awk 或其他命令进行此类文本提取?
我试图寻找一些类似的解决方案来解决我的问题,但未能找到。
更新:至少会有
答案1
通过grep
PCRE 支持的实现,并且-o
:
$ grep -P -o '(?<![^_])\p{Lu}[^_]*_\p{Ll}[^_]*' < your-file
Today_is
Doesnt_rain
Like_rainy
(如果您不支持,可以替换grep -P
为)。pcregrep
grep
-P
这是一个u
大写字母L
,后跟 0 个或多个非_
- ,然后是_
,一个l
小写字母L
和另一个 0 个或多个非_
- 的序列,整个事物仅匹配,前提是它不跟随非 - _
(即,跟随_
或行的开头)。
这将在其自己的行上打印每个匹配的出现。要将其限制为每行的第一个匹配项,您可以采取不同的方法:
grep -P -o '^(.*?_)??\K\p{Lu}[^_]*_\p{Ll}[^_]*' < your-file
对于每行的最后一个匹配,相同,但对于吃掉前导部分的部分使用运算符的贪婪版本:
grep -P -o '^(.*_)?\K\p{Lu}[^_]*_\p{Ll}[^_]*' < your-file
答案2
$ grep -o '[[:upper:]][[:alpha:]]*_[[:lower:]][[:alpha:]]*' file
Today_is
Doesnt_rain
Like_rainy
这会提取以大写字母开头、后跟任意数量的字母字符、下划线、后跟小写字母和(可能)更多字母字符的任何字符串。
然而,如果有多个匹配项,上面的代码会在每行中提取多个匹配项。
以下sed
命令没有这个问题(它会提取最后的每行都有这样的字符串):
$ sed -n 's/.*\([[:upper:]][[:alpha:]]*_[[:lower:]][[:alpha:]]*\).*/\1/p' file
Today_is
Doesnt_rain
Like_rainy
答案3
awk 方法
awk -F'_' -v OFS='_' '{
for (i=1; i<NF; i++) {
if ($i ~ /^[[:upper:]]/ && $(i+1) ~ /^[[:lower:]]/) {
print $i, $(i+1)
break
}
}
}' file
确保break
仅打印第一个匹配项。
答案4
sed 's/.*\([A-Z][^_]*_[a-z][^_]*\).*/\1/' <your-file
编辑:贪婪的 sed 给出最后一个匹配。第一个匹配的 awk 解决方案:
awk '{match($0,/([A-Z][^_]*_[a-z][^_]*)/,a); print a[1]}' <your-file