如何提取一些落在某个范围内的值

如何提取一些落在某个范围内的值

我有大约 4500 行氨基酸变体,如下所示:

S1437T
H1266Y
T2662A
E1397A
E626K
S1538T
E3021K

简而言之,数字两侧的字母是氨基酸残基,数字代表残基位置。我只想检索 2400 到 3100 范围内的那些变化。

我尝试使用grep但没有那么成功。另外,我知道这awk对于这种操作可能会更好,但我在这方面完全是菜鸟awk。任何帮助,将不胜感激。

答案1

提取perl第一个数字序列\d+并随后检查其值:

$ perl -ne 'print if /\d+/ && $& >= 2400 && $& <= 3100' < your-file
T2662A
E3021K

答案2

使用大写字母作为 的分隔符awk,我们可以查看第二个字段来确定是否应该提取该行:

$ awk -F '[[:upper:]]' '$2 >= 2400 && $2 <= 3100' file
T2662A
E3021K

事实上,由于使用包含数字和非数字混合的字段作为数字会将该字段转换为数字,并在第一个非数字处停止,因此将行上的第一个字符视为分隔符就足够了:

$ awk -F '^.' '$2 >= 2400 && $2 <= 3100' file
T2662A
E3021K

对于sed,它有点棘手,因为该工具在算术方面非常糟糕。下面的命令只是作为一种有趣的干扰而包含在内。

在这里,我们将三个正则表达式与输入数据中的每一行进行匹配,如果匹配则打印该行。第一个表达式处理范围 2400-2999,而第二个表达式处理范围 3000-3099。我们用第三个表达式单独测试 3100。在每个测试中,我们要求数字的两侧出现一个大写字符。

$ sed -n \
    -e '/^[[:upper:]]2[4-9][0-9][0-9][[:upper:]]$/p' \
    -e '/^[[:upper:]]30[0-9][0-9][[:upper:]]$/p' \
    -e '/^[[:upper:]]3100[[:upper:]]$/p' file
T2662A
E3021K

稍长的编辑脚本可以更有效地执行测试:

$ sed \
    -e '/^[[:upper:]]2[4-9][0-9][0-9][[:upper:]]$/b' \
    -e '/^[[:upper:]]30[0-9][0-9][[:upper:]]$/b' \
    -e '/^[[:upper:]]3100[[:upper:]]$/b' \
    -e d file
T2662A
E3021K

不带参数的命令b使脚本分支到末尾,其中隐式打印操作输出当前行。d对于不包含匹配项的行执行最终命令。这确保了具有匹配项的行不会被测试过多的次数。

答案3

awk从当前行 ( )中删除前导和尾随字母r

awk '{r=$0; gsub(/^[A-Z]/,"",r); gsub(/[A-Z]$/,"",r)} r>=2400 && r<=3100' file

输出:

T2662A
E3021K

答案4

Python 具有链式比较功能,可以紧密地转换为意图。

python3 <<\eof
with open('file') as f:
  for l in f:
    n = int(l[1:-2])
    if 2400 <= n <= 3100:
      print(l,end="")
eof
T2662A
E3021K

还可以创建一个范围对象并进行比较因此我们可以用以下内容替换链式比较:

if n in range(2400,3100+1):

我们可以使用perl的grep命令来搜索该数字是否存在。

perl -lne 'my $n = s/\D//gr;
  print if grep(/^$n$/,2400..3100);
' file

在这里,我们使用 GNU sed 来预处理 GNU dc 命令的数据,然后通过比较乘积 (num-lowerlim)x(upperlim-num) >= 0 来检查范围成员资格以符合打印资格。

sed -Ee '
  h;s/.(.*)./\1/
  x;s/.*/[&]/;G;
  s/\n/ /
' file |
dc -e "
[q]sq [p]sp
[2400-r3100r-*0!>p]su
[?z0=q dlux c z0=?]s?
l?x
"

在这个方法中,我们首先从第二列开始对数字进行排序

sort -k1.2n file |
awk '{n=0+substr($0,2)}
n < 2400 {next}
n > 3100 {exit}
1'

相关内容