根据一定的标准选择线

时间:2013-07-06 04:18:05

标签: python perl awk

我有十列中的数据列表,如下所示。它有几千行。

$1  $2    $3    $4   $5     $6      $7    $8    $9  $10

|  8455 105@O13  |  8132  101@H13  8131  101@O13 |  68.43
|  7490 93@O16   |  8868  110@H16  8867  110@O16 |  68.30
|  7561 94@O12   |  9185  114@H13  9184  114@O13 |  66.83
|  8776 109@O12  |  7481  93@H12   7480  93@O12  |  65.55
|  8867 110@O16  |  8432  105@H23  8431  105@O23 |  64.48
|  9832 122@O13  |  6357  79@H16   6356  79@O16  |  64.44
|  9194 114@O15  |  5699  71@H12   5698  71@O12  |  64.06
|  8849 110@O25  |  5780  72@H12   5779  72@O12  |  63.99

我想从第3列和第6列中选择与某些特殊表达式匹配的行。我想用作正则表达式的标准是“之前的数字”@“符号在两列中都相同”。如果匹配此条件,则我想将这些行打印到新文件。

我在awk中尝试过这样的事情

awk '$3~/[1@]/  {print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10}' hhHB_inSameLayer_065_128-maltoLyo12per.tbl

但它没有给出我想要的东西。

如果有人可以提供一些帮助,我很赞成。

注意:如果我在perl或python中得到一些帮助,也会感激。

非常感谢提前。

7 个答案:

答案 0 :(得分:4)

在awk中尝试以下操作。将$3$6拆分为基于@分隔符的数组,并打印每个匹配项的第一个元素

awk '{split($3, a, "@"); split($6, b, "@");if (a[1] == b[1]) print}'

或更具惯用力

awk '{split($3, a, "@"); split($6, b, "@")}; a[1] == b[1]' 

或快速Python 2.6+解决方案

from __future__ import print_function
with open('testfile.txt') as f:
    for line in f:
            fields = line.split()
            fields3 = fields[2].split('@')
            fields6 = fields[5].split('@')
            if fields3[0] == fields6[0]:
                    print(line, end='')

答案 1 :(得分:2)

GNU代码

sed -r '/^\|\s+\S+\s+([0-9]+@).*\|.*\1/!d' file

假设有两行标题:

sed -r '1,2p;/^\|\s+\S+\s+([0-9]+@).*\|.*\1/!d' file

答案 2 :(得分:1)

这是一个Perl单行程序,它使用带有反向引用的单个正则表达式模式:

perl -ne 'print if m/^\S+\s+\S+\s+(\d+\@)\S+\s+\S+\s+\S+\s+\1/' hhHB_inSameLayer_065_128-maltoLyo12per.tbl > hhHB_inSameLayer_065_128-maltoLyo12per_reduced.tbl

(我很惊讶没有人指出Vijay原始问题陈述中的明显缺陷:示例中没有符合规定标准的记录。)

答案 3 :(得分:0)

这是一个使用内置csv模块的Python解决方案。它会在列表stored_lines中存储符合条件的所有行。

** 编辑跳过标题,不将多个空格视为多个分隔符。 **

import csv

def is_good(line):
    return line[2][:line[2].find('@')] == line[5][:line[5].find('@')]

# we'll put the lines that match the criteria here.
stored_lines = []

with open('stack.txt') as fr:
    csv_reader = csv.reader(fr, delimiter=' ', skipinitialspace=True)

    # Skip the header
    csv_reader.next()
    csv_reader.next()
    for line in csv_reader:
         if is_good(line): stored_lines.append(line)

print(stored_lines)

答案 4 :(得分:0)

在我甚至可以鞭打之前叹了口气,三个解决方案......

import re

write_file = open("sorted data.txt", "w")

with open("data.txt", "r") as read_file:
    for line in read_file:
        data_list = re.split("[\s\|@]+", line)
        if data_list[2] == data_list[5]:
            write_file.write(line)

write_file.close()

我担心我对perl或awk的了解不多,但这对re.split来说这很好看并且可读。

答案 5 :(得分:0)

Perl:

while( <DATA> ){

  # split the line by whitespace
  my @columns = split;

  # get number from column 3
  my ( $value_col_3 ) = $columns[2] =~ m{ \A (\d+) \@ }msx;

  # get number from column 6
  my ( $value_col_6 ) = $columns[5] =~ m{ \A (\d+) \@ }msx;

  if( $value_col_3 == $value_col_6 ){
    print;
  }
}

__DATA__
|  8455 105@O13  |  8132  101@H13  8131  101@O13 |  68.43
|  7490 93@O16   |  8868  110@H16  8867  110@O16 |  68.30
|  7561 94@O12   |  9185  114@H13  9184  114@O13 |  66.83
|  8776 109@O12  |  7481  93@H12   7480  93@O12  |  65.55
|  8867 110@O16  |  8432  105@H23  8431  105@O23 |  64.48
|  9832 122@O13  |  6357  79@H16   6356  79@O16  |  64.44
|  9194 114@O15  |  5699  71@H12   5698  71@O12  |  64.06
|  8849 110@O25  |  5780  72@H12   5779  72@O12  |  63.99

答案 6 :(得分:0)

import re

su = '''
$1  $2    $3    $4   $5     $6      $7    $8    $9  $10

|  8455 105@O13  |  8132  101@H13  8131  101@O13 |  68.43
|  7490 93@O16   |  8868  110@H16  8867  110@O16 |  68.30
|  7561 94@O12   |  9185  94@H13  9184  114@O13 |  66.83
|  8776 109@O12  |  7481  93@H12   7480  93@O12  |  65.55
|  8867 110@O16  |  8432  105@H23  8431  105@O23 |  64.48
|  9832 122@O13  |  6357  79@H16   6356  79@O16  |  64.44
|  9194 114@O15  |  5699  71@H12   5698  71@O12  |  64.06
|  8849 110@O25  |  5780  72@H12   5779  72@O12  |  63.99'''

f = re.compile(
    '(^\|[^|]+?[ \t](\S+?)@\S+[ \t]+?'
    '\|[^|]+?[ \t](\\2)@\S+.+)',
    re.MULTILINE)\
    .finditer

print [m.group(1) for m in f(su)]