awk/sed 查找字符串中第一个和最后一个大写字母的索引

awk/sed 查找字符串中第一个和最后一个大写字母的索引

我有几种这样的字符串:

示例字符串1

--AbbbAnde---

示例字符串2

abksjiRNNBBKUGFLYFYLF

示例字符串3

-ankNUGUYUBUIGCafrg--

示例字符串4

BNKJUGFVULNK-Kew---

PS:不存在包含零个或一个大写字母的字符串。

我想通过 awk、sed 或其他 bash 程序从看起来像上面示例的字符串中找到第一个和最后一个大写字母的索引,因为我有数千个文件,而 Python 会很耗时。第一个大写字母的索引应该是从开始到结束(从左到右)的计数。而最后一个大写字母的索引应该是从结束到开始(从右到左)的计数。

例如,

对于示例 string1,第一个大写字母是 A,索引是3从左到右(开始到结束)。最后一个大写字母是 A,索引是7从结束到开始。

对于示例 string2,第一个大写字母是 R,索引是7从左到右(开始到结束)。最后一个大写字母是F,索引是1从结束到开始。

对于示例 string3,第一个大写字母是 N,索引是5从左到右(开始到结束)。最后一个大写字母是C,索引是7从结束到开始。

对于示例 string4,第一个大写字母是 B,索引是1从左到右(开始到结束)。最后一个大写字母是 K,索引是6从结束到开始。

感谢您的帮助。

答案1

awk '
{
    start = match($0, /[A-Z]/)
    end   = match($0, /[A-Z][^A-Z]*$/)
    print (start ? start : "NaN"), (end ? length() - end + 1 : "NaN")
}' infile

答案2

$ awk '
    match($0,/[[:upper:]](.*[[:upper:]])?/) {
        print $0, RSTART, length()-(RSTART+RLENGTH-2)
    }
' file
xyzAb 4 2
--AbbbAnde--- 3 7
abksjiRNNBBKUGFLYFYLF 7 1
-ankNUGUYUBUIGCafrg-- 5 7
BNKJUGFVULNK-Kew--- 1 6

以上是在此输入上运行的:

$ cat file
xyzAb
--AbbbAnde---
abksjiRNNBBKUGFLYFYLF
-ankNUGUYUBUIGCafrg--
BNKJUGFVULNK-Kew---

答案3

使用 AWK 很容易获得前导部分或尾随部分的长度。加 1 即可得到问题中所示的索引。

echo '--AbbbAnde---
abksjiRNNBBKUGFLYFYLF
-ankNUGUYUBUIGCafrg--
BNKJUGFVULNK-Kew---
foobarbaz' | awk '{

    printf("string %s\n", $0);
    head=tail=$0;

    sub(/[A-Z].*$/,"",head);
    sub(/^.*[A-Z]/,"",tail);

    printf("head <%s> %d\n", head, length(head)+1);
    printf("tail <%s> %d\n", tail, length(tail)+1);
}'

输出:

string --AbbbAnde---
head <--> 3
tail <nde---> 7
string abksjiRNNBBKUGFLYFYLF
head <abksji> 7
tail <> 1
string -ankNUGUYUBUIGCafrg--
head <-ank> 5
tail <afrg--> 7
string BNKJUGFVULNK-Kew---
head <> 1
tail <ew---> 6
string foobarbaz
head <foobarbaz> 10
tail <foobarbaz> 10

您可能需要扩展脚本以处理不包含大写字母的输入。 (这个问题并没有告诉你在这种情况下你会期望什么结果。)

答案4

POSIX awk,字段分隔符为大写正则表达式。

LC_ALL=C \
awk -F '[A-Z]' '
NF>2{
  print length("x"$1), length("x"$NF)
}' file

Perl 有 index 和 rindex 内置函数,分别从前端和末尾获取子字符串的索引(从零开始)。但在此之前,我们将所有大写字母转换为 A,因为内置索引不执行正则表达式。

perl -lne '1 < tr/A-Z/A/ and
  print 1+index($_,"A"), $",
    length()-rindex($_,"A");
' file

具有扩展正则表达式模式的 GNU sed (-E)

LC_ALL=C \
sed -E 'h;
  s/[A-Z].*/./
  :a
    s/./a/g;tb
    :b
      s/^a/c/
      s/([b-j])a/\u\1/
      y/BCDEFGHIJ/cdefghijk/
      s/ka/ab/
    tb
    y/bcdefghijk/0123456789/
    G;P
    /\n$/d
    z;x
    s/.*[A-Z]/./
  ba
' file | paste -d" " - -

输出:

3 7
7 1
5 7
1 6

相关内容