我有十列中的数据列表,如下所示。它有几千行。
$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中得到一些帮助,也会感激。
非常感谢提前。
答案 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:
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)]