2015-03-04 3 views
1

ввода выглядит следующим образом:Python Найти Дублирование с Note Струнного Сохранением

assign (resid 3 and name H) (resid 18 and name H) 2.5 2.5 2.5 ! note string 1 
assign (resid 16 and name H) (resid 5 and name H) 2.5 2.5 2.5 ! note string 2 
assign (resid 42 and name H) (resid 55 and name H) 2.5 2.5 2.5 ! note string 3 
assign (resid 44 and name H) (resid 53 and name H) 2.5 2.5 2.5 ! note string 4 
assign (resid 53 and name H) (resid 44 and name H) 2.5 2.5 2.5 ! note string 5 

Если вы обратите внимание, здесь, строка 4 является 5 являются дубликаты здесь только (resid 44 and name H) и (resid 53 and name H) переключается. Мой идеальный выход возвращает что-то вроде этого:

assign (resid 3 and name H) (resid 18 and name H) 2.5 2.5 2.5 ! note string 1 
assign (resid 16 and name H) (resid 5 and name H) 2.5 2.5 2.5 ! note string 2 
assign (resid 42 and name H) (resid 55 and name H) 2.5 2.5 2.5 ! note string 3 
assign (resid 44 and name H) (resid 53 and name H) 2.5 2.5 2.5 ! DUPLICATE ! note string 4 ! note string 5 

Так я получил работу с обычным способом чтения файла в Python.

txt = open(filename) 

print (lines[0]) 

Я, очевидно, необходимо, чтобы захватить строки между ( и ), а затем сделать некоторый тип поиска. Я захватил тех, у кого было регулярное выражение, которое было детским материалом. Моя идея состояла в том, чтобы использовать match[0] и match[1] внутри вложенного цикла и выполнять поиск. Моя неудачная попытка является:

for i in lines: 
# match = re.search("\\(.*?\\)", i) 
    match = re.findall('\\(.*?\\)',i) 
    for x in i: 
     mm = re.search("match[0] match[1]", lines) 
     print (mm) 

match[0] и match[1] дать мне то, что я хочу, если я их печатать. Каков наилучший способ сделать этот поиск, чтобы я мог сохранить и перенести флаг примечания? Я полагаю, что добавление DUPLICATE к ноте будет тривиально.

Меня действительно интересует только решение python. Мне также нужно использовать это для 400-строчной программы, которую я пишу.

Благодаря

ответ

2

Кто-то, кто является более опытным, используя регулярное выражение, возможно, может направить вас к более хорошей реализации, чтобы получить ключ, но хранить кортежи в качестве ключей и задним ходом, чтобы проверить, если он уже существует должно работать:

lines = """assign (resid 3 and name H) (resid 18 and name H) 2.5 2.5 2.5 ! note string 1 
assign (resid 16 and name H) (resid 5 and name H) 2.5 2.5 2.5 ! note string 2 
assign (resid 42 and name H) (resid 55 and name H) 2.5 2.5 2.5 ! note string 3 
assign (resid 44 and name H) (resid 53 and name H) 2.5 2.5 2.5 ! note string 4 
assign (resid 53 and name H) (resid 44 and name H) 2.5 2.5 2.5 ! note string 5""" 

import re 

d = {} 

r1 = re.compile(r"(?<=\))\s") 
r2 = re.compile(r"\(.*\)") 

for line in lines.splitlines(): 
    key = tuple(r1.split(r2.findall(line)[0])) 
    # ("foo","bar") == ("bar","foo") , also check current key is not in d 
    if tuple(reversed(key)) not in d and key not in d: 
     d[key] = line 

pp(list(d.values())) 

Выход:

['assign (resid 42 and name H) (resid 55 and name H) 2.5 2.5 2.5 ! note ' 
'string 3', 
'assign (resid 16 and name H) (resid 5 and name H) 2.5 2.5 2.5 ! note ' 
'string 2', 
'assign (resid 3 and name H) (resid 18 and name H) 2.5 2.5 2.5 ! note ' 
'string 1', 
'assign (resid 44 and name H) (resid 53 and name H) 2.5 2.5 2.5 ! note ' 
'string 4'] 

Если порядок имеет значение использовать collections.Ordereddict. Я не уверен, что именно вы хотите добавить в строку, но это добавит DUPLICATE ! string 5 и т.д .. к существующему значению ключа:

from collections import OrderedDict 

d = OrderedDict() 
import re 

r1 = re.compile(r"(?<=\))\s") 
r2 = re.compile(r"\(.*\)") 
for line in lines.splitlines(): 
    key = tuple(r1.split(r2.findall(line)[0])) 
     # (resid 44 and name H) (resid 53 and name H) -> (resid 53 and name H) (resid 44 and name H) 
    rev_k = tuple(reversed(key)) 
    if rev_k in d: 
     d[rev_k] += " DUPLICATE " + " ".join(line.rsplit(None,4)[1:]) 
    elif key in d: 
     d[key] += " DUPLICATE " + " ".join(line.rsplit(None,4)[1:]) 
    else: 
     d[key] = line 

Выход:

['assign (resid 3 and name H) (resid 18 and name H) 2.5 2.5 2.5 ! note ' 
'string 1', 
'assign (resid 16 and name H) (resid 5 and name H) 2.5 2.5 2.5 ! note ' 
'string 2', 
'assign (resid 42 and name H) (resid 55 and name H) 2.5 2.5 2.5 ! note ' 
'string 3', 
'assign (resid 44 and name H) (resid 53 and name H) 2.5 2.5 2.5 ! note ' 
'string 4 DUPLICATE ! string 5'] 

в зависимости от того, что вы хотите сделать вы можете добавить оригинальную линию и DUPLICATE ! string ... каждый раз, так что исходная строка, прежде чем мы увидели DUP будет первым элементом, а остальное будет все DUPLICATE ! string ...:

lines = """assign (resid 3 and name H) (resid 18 and name H) 2.5 2.5 2.5 ! note string 1 
assign (resid 16 and name H) (resid 5 and name H) 2.5 2.5 2.5 ! note string 2 
assign (resid 42 and name H) (resid 55 and name H) 2.5 2.5 2.5 ! note string 3 
assign (resid 44 and name H) (resid 53 and name H) 2.5 2.5 2.5 ! note string 4 
assign (resid 53 and name H) (resid 44 and name H) 2.5 2.5 2.5 ! note string 5 
assign (resid 53 and name H) (resid 44 and name H) 2.5 2.5 2.5 ! note string 6""" 

from collections import defaultdict 


d = defaultdict(list) 
r1 = re.compile(r"(?<=\))\s") 
r2 = re.compile(r"\(.*\)") 

for line in lines.splitlines(): 
    key = tuple(r1.split(r2.findall(line)[0])) 
    rev_k = tuple(reversed(key)) 
    if rev_k in d: 
     d[rev_k].append(line + " DUPLICATE " + " ".join(line.rsplit(None,4)[1:])) 
    elif key in d: 
      d[key] += " DUPLICATE " + " ".join(line.rsplit(None,4)[1:]) 
    else: 
     d[key].append(line) 


    pp(list(d.values())) 

Выход:

[['assign (resid 3 and name H) (resid 18 and name H) 2.5 2.5 2.5 ! note ' 
    'string 1'], 
['assign (resid 44 and name H) (resid 53 and name H) 2.5 2.5 2.5 ! note ' 
    'string 4', 
    'assign (resid 53 and name H) (resid 44 and name H) 2.5 2.5 2.5 ! note ' 
    'string 5 DUPLICATE ! note string 5', 
    'assign (resid 53 and name H) (resid 44 and name H) 2.5 2.5 2.5 ! note ' 
    'string 6 DUPLICATE ! note string 6'], 
['assign (resid 42 and name H) (resid 55 and name H) 2.5 2.5 2.5 ! note ' 
    'string 3'], 
['assign (resid 16 and name H) (resid 5 and name H) 2.5 2.5 2.5 ! note ' 
    'string 2']] 
+0

То, что вы действительно могли бы сделать более простой, но, как вы знаете, что строка будет содержать '' DUPLICATE? ('DUPLICATE! Note string 4! Note string 5') вы просто написали' примечание' в конце строк как свою сложную часть проблемы: D – Kasramvd

+0

вы можете попробовать эту строку и дать мне результат? 'Assign (остаток 3 и имя H) (остаток 18 и имя H) 2,5 2,5 2,5! строка примечания 1 присвоить (остаток 16 и имя Н) (остаток 5 и имя Н) 2,5 2,5 2,5! строка примечания 2 назначить (остаток 5 и имя H) (остаток 16 и имя H) 2,5 2,5 2,5! строка примечания 3 назначить (остаток 16 и имя H) (остаток 5 и имя H) 2,5 2,5 2,5! строка примечания 4 назначить (остаток 57 и имя H) (остаток 44 и имя H) 2,5 2,5 2,5! note string 5' – Kasramvd

+0

И для поиска дубликата после извлечения строки между '()' просто используйте 'sorted'! – Kasramvd

0

Построение простой словарь (или OrderedDict) с отсортированных значений в качестве ключа и всей линии (или записки) в качестве значения.

Давайте предположим, что это то, что вы хотите быть уникальным:

>>> re.findall("\(.*?\)", lns[3]) 
['(resid 44 and name H)', '(resid 53 and name H)'] 

Таким образом, вы можете подготовить упорядоченный ключ:

>>> tmp1 = set(re.findall("\(.*?\)", lns[3])) # Line 4 
>>> tmp2 = set(re.findall("\(.*?\)", lns[4])) # Line 5 
>>> tmp1 
{'(resid 44 and name H)', '(resid 53 and name H)'} 
>>> tmp2 
{'(resid 44 and name H)', '(resid 53 and name H)'} 
>>> tmp1 == tmp2 

Но set является unhashable так что вы должны преобразовать его в например tuple, поэтому его можно использовать как key for dictionary:

Клавиши словаря - почти произвольные значения. Значения, которые не являются хешируемыми, то есть значения, содержащие списки, словари или другие изменяемые типы (которые сравниваются по значению, а не по идентификатору объекта), не могут использоваться в качестве ключей.

key = tuple(set((re.findall("\(.*?\)", lns[3])))) 

Не нужно просто хранить строку и, возможно рассчитывать ключей?

result = {} 

with open(filename, 'r') as file: 
    for line in file: 
     key = tuple(set((re.findall("\(.*?\)", line)))) 

     if key in result: 
      result[key][3] += 1 
     else: 
      result[key] = [line.strip(), 1] 

for line, count in result.values(): 
    print('Seen line', line, count, 'times') 

Или хранить каждую строку с ключом:

result = collections.defaultdict(list) 

# ... 
     key = tuple(set((re.findall("\(.*?\)", line)))) 

     result[key].append(line.strip()) 

# And nice printing 
for key, lines in result.items(): 
    print('Seen', key, 'on following lines:') 
    for l in lines: 
     print('\t', l) 
    print() 
Смежные вопросы