我有两个相当大的.txt文件,其中包含类似的ID标签。我需要做的是从一个文件中获取ID标记,在另一个文件中匹配它,并将ID替换为第一个文件中的名称。我需要为1000多个标签完成此操作。关键是要从第一个文件中精确匹配ID标记名称的一部分并替换它。
每行有一个唯一的ID标记,两个文件之间总是完全匹配(对于位置[6-16] =“10737.G1C22”);匹配是分散的,因此File1.txt中的第1行可能与File2.txt中的第504行匹配
两个文件中的行顺序无法排序且必须维护
例如:
File1.txt =
TYPE1_10737.G1C22 ---------
...
File2.txt =
10737.G1C22 ----------
我需要File1.txt中的名称,特别是“10737.G1C22”来找到它在File2.txt中的完全匹配并将其替换为“TYPE1_10737.G1C22”。
编辑然后看起来像这样,现在File2.txt中的名称根据File1.txt中的匹配进行了更改:
File2.txt =
TYPE1_10737.G1C22 ---------
...
我尝试了一些sed功能,但卡住了。重要的是,只有找到完全匹配后,名称的前6个字符才会更改,而不是其他任何字符。有超过1000多个ID标签需要匹配和更改。
我正在考虑代码,它告诉它完全匹配位置[6-16]并将其替换为File1.txt中的[0-16]。
非常感谢任何帮助。这甚至可能吗?我也愿意接受其他建议。谢谢。
答案 0 :(得分:1)
ed
解决方案步骤1.创建或多或少看起来像你的File1.txt
和File2.txt
进行实验并获得一些乐趣(1000行)。使用此脚本(在暂存目录中):
#!/bin/bash
declare -A table
while ((${#table[@]}!=1000)); do
key=$(mktemp -u XXXXXXXXXX)
key=${key:0:5}.${key:5}
table[${key^^}]=1
done
{
for key in "${!table[@]}"; do
echo "TYPE1_$key some junk here" >&3
echo "$key some more junk here"
done | shuf > File2.txt
} 3> File1.txt
步骤2.使用标准编辑器ed
进行替换,包含在此脚本中:
#!/bin/bash
ed -s File2.txt < <(
while read l _; do
p=${l:6}
p=${p//./\\.}
echo "%s/^$p/$l/"
done < File1.txt
echo wq
)
这假定您只有字母数字字符,下划线_
和句点.
。如果您有其他字符,请进行适当修改(以免与正则表达式冲突)。
第3步。检查并享受:
vimdiff <(sort File1.txt) <(sort File2.txt)
完成。
注意。由于ed
是一个真正的编辑器,所以替换是在适当的位置完成的。 File2.txt
实际上是已编辑。
嘿,等等我可能用16个字符忽略了你的要求......我使用了你的模式后面有空格的事实。如果我的解决方案在这一点上不好,请告诉我,我会适当修改它。
答案 1 :(得分:1)
基于Python的解决方案很简单,但请注意,这不能就地完成,您必须将结果存储到某个新位置,例如tempfile。
如果您的文件不是非常大,即您可以在内存中构建映射,则它是直接的(假设1)名称与带有下划线的id分隔,2)id与带空格的文本分隔,如示例3)每行包含id和name 4)file1中只存在每个id一个名称:
file1 = ('TYPE1_10737.G1C22 ---------', )
file2 = ('10737.G1C22 +++++++++++', )
id_name_gen = (l.split(' ', 1)[0] for l in file1)
id2name_mapping = {line.split('_', 1)[1]: line for line in id_name_gen}
一旦你有了映射,就可以轻松完成替换(如果找不到匹配项,保持字符串不变):
id_rest_gen = (l.split(' ', 1) for l in file2)
file2updated_gen = ('{} {}'.format(id2name_mapping.get(id, id), rest) for id, rest in file2)
>>> list(file2updated_gen)
['TYPE1_10737.G1C22 +++++++++++']
您只需将生成的生成器存储到文件中。
答案 2 :(得分:1)
python中的一个简单解决方案:
from collections import OrderedDict
LINES_PER_CYCLE = 1000
with open('output.txt', 'wb') as output, open('test_2.txt', 'rb') as fin:
fin_line = ''
# Loop until fin reaches EOF.
while True:
cache = OrderedDict()
# Fill the cache with up to LINES_PER_CYCLE entries.
for _ in xrange(LINES_PER_CYCLE):
fin_line = fin.readline()
if not fin_line:
break
key, rest = fin_line.strip().split(' ', 1)
cache[key] = ['', rest]
# Loop over the file_1.txt to find tags with given id.
with open('test_1.txt', 'rb') as fout:
for line in fout:
tag, _ = line.split(' ', 1)
_, idx = tag.rsplit('_', 1)
if idx in cache:
cache[idx][0] = tag
# Write matched lines to the output file, in the same order
# as the lines were inserted into the cache.
for _, (tag, rest) in cache.iteritems():
output.write('{} {}\n'.format(tag, rest))
# If fin has reached EOF, break.
if not fin_line:
break
它的作用是从LINES_PER_CYCLE
读取file_2.txt
个条目,查找file_1.txt
中的匹配条目并写入输出。由于内存有限(缓存),多次搜索file_1.txt
。
这假定tag / id部分由-------
的空格分隔,并且标记和id由下划线与它们自己分开,即。 &#39; tag_idx blah blah&#39;。
答案 3 :(得分:1)
我会将第一个文件加载到dict中,然后处理第二个文件以匹配键,将任何更改输出到第3个文件:
import re
# Pattern to match in File1
pattern1 = "(\w+)_(\d+\.\w+)\s+.*$"
# Pattern to match in File2
pattern2 = "(\d+\.\w+)\s+.*$"
# Load the 'master' file into a dict,
# with the number as key and 'type' as value.
file1_dict = dict()
with open("File1.txt", "r") as f:
for line in f.readlines():
m = re.match(pattern1, line)
if m:
file1_dict[m.group(2)] = m.group(1)
# Open a new output file to replace File2.txt
with open("File3.txt", "w") as fnew:
# As you process each line in File2.txt,
# find matching entry in above File1 list.
# Either write the old unmatched value or new
# matching, changed value to File3.txt
with open("File2.txt", "r") as f:
for line in f.readlines():
is_found = False
m = re.match(pattern2, line)
if m:
if m.group(1) in file1_dict:
is_found = True
fnew.write("{0}_{1}".format(file1_dict[m.group(1)], line))
if not is_found:
fnew.write(line)
# Then just overwrite File2.txt with new File3.txt contents.
# Original File1.txt
TYPE1_10737.G1C22 ---------
TYPE1_10738.G1C22 ---------
TYPE1_10739.G1C22 ---------
TYPE1_10740.G1C22 ---------
TYPE1_10741.G1C22 ---------
TYPE1_10742.G1C22 ---------
TYPE1_10799.G1C22 ---------
# Original File2.txt
10737.G1C22 ---------
10738.G1C22 ---------
10739.G1C22 ---------
10740.G1C22 ---------
10788.G1C22 ---------
10741.G1C22 ---------
10742.G1C22 ---------
# Results of new File3.txt
TYPE1_10737.G1C22 ---------
TYPE1_10738.G1C22 ---------
TYPE1_10739.G1C22 ---------
TYPE1_10740.G1C22 ---------
10788.G1C22 ---------
TYPE1_10741.G1C22 ---------
TYPE1_10742.G1C22 ---------