提取以大写字母开头的列,然后提取以小写字母开头的下一列

提取以大写字母开头的列,然后提取以小写字母开头的下一列

我有一个包含多列的文件,各列之间用下划线 (_) 分隔。

大多数列的第一个字符以大写字母开头,有些以小写字母开头。

我打算提取每一行的字符串,该字符串以大写字母开头,下一列以小写字母开头。每一条线都会至少发生一次这样的情况。(更新:如果只有第一场比赛就太好了)。棘手的部分是这种情况不会发生在每一行的同一列。

例如:

Today_is_a_Good_Day
It_Doesnt_rain
i_dont_Like_rainy_day

期望的输出:

Today_is
Doesnt_rain
Like_rainy

有没有办法使用 grep/sed/awk 或其他命令进行此类文本提取?

我试图寻找一些类似的解决方案来解决我的问题,但未能找到。

更新:至少会有

答案1

通过grepPCRE 支持的实现,并且-o

$ grep -P -o '(?<![^_])\p{Lu}[^_]*_\p{Ll}[^_]*' < your-file
Today_is
Doesnt_rain
Like_rainy

(如果您不支持,可以替换grep -P为)。pcregrepgrep-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

相关内容