Каков наилучший способ удалить повторяющиеся строки, соответствующие регулярному выражению из строки, используя Python? - PullRequest
2 голосов
/ 03 октября 2008

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

Просто чтобы прояснить ... регулярное выражение .*Dog.* займет

Cat
Dog
My Dog
Her Dog
Mouse

и возврат

Cat
Dog
::::: Pattern .*Dog.* repeats 2 more times.
Mouse


#!/usr/bin/env python
#

import re
import types

def remove_repeats (l_string, l_regex):
   """Take a string, remove similar lines and replace with a summary message.

   l_regex accepts strings and tuples.
   """

   # Convert string to tuple.
   if type(l_regex) == types.StringType:
      l_regex = l_regex,


   for t in l_regex:
      r = ''
      p = ''
      for l in l_string.splitlines(True):
         if l.startswith('::::: Pattern'):
            r = r + l
         else:
            if re.search(t, l): # If line matches regex.
                m += 1
                if m == 1: # If this is first match in a set of lines add line to file.
                   r = r + l
                elif m > 1: # Else update the message string.
                   p = "::::: Pattern '" + t + "' repeats " + str(m-1) +  ' more times.\n'
            else:
                if p: # Write the message string if it has value.
                   r = r + p
                   p = ''
                m = 0
                r = r + l

      if p: # Write the message if loop ended in a pattern.
          r = r + p
          p = ''

      l_string = r # Reset string to modified string.

   return l_string

Ответы [ 3 ]

1 голос
/ 03 октября 2008

Обновлен ваш код, чтобы быть немного более эффективным

#!/usr/bin/env python
#

import re
import types

def remove_repeats (l_string, l_regex):
   """Take a string, remove similar lines and replace with a summary message.

   l_regex accepts strings/patterns or tuples of strings/patterns.
   """

   # Convert string/pattern to tuple.
   if not hasattr(l_regex, '__iter__'):
      l_regex = l_regex,

   ret = []
   last_regex = None
   count = 0

   for line in l_string.splitlines(True):
      if last_regex:
         # Previus line matched one of the regexes
         if re.match(last_regex, line):
            # This one does too
            count += 1
            continue  # skip to next line
         elif count > 1:
            ret.append("::::: Pattern %r repeats %d more times.\n" % (last_regex, count-1))
         count = 0
         last_regex = None

      ret.append(line)

      # Look for other patterns that could match
      for regex in l_regex:
         if re.match(regex, line):
            # Found one
            last_regex = regex
            count = 1
            break  # exit inner loop

   return ''.join(ret)
1 голос
/ 03 октября 2008

Кажется, что функция ревантера делает то, что вы хотите:

def rematcher(re_str, iterable):

    matcher= re.compile(re_str)
    in_match= 0
    for item in iterable:
        if matcher.match(item):
            if in_match == 0:
                yield item
            in_match+= 1
        else:
            if in_match > 1:
                yield "%s repeats %d more times\n" % (re_str, in_match-1)
            in_match= 0
            yield item
    if in_match > 1:
        yield "%s repeats %d more times\n" % (re_str, in_match-1)

import sys, re

for line in rematcher(".*Dog.*", sys.stdin):
    sys.stdout.write(line)

EDIT

В вашем случае последняя строка должна быть:

final_string= '\n'.join(rematcher(".*Dog.*", your_initial_string.split("\n")))
0 голосов
/ 09 августа 2009

Во-первых, ваше регулярное выражение будет соответствовать медленнее, чем если бы вы прекратили жадное совпадение.

.*Dog.*

эквивалентно

Dog

, но последний совпадает быстрее, потому что не происходит возврата. Чем длиннее струны, тем более вероятно, что «Собака» появляется несколько раз, и, следовательно, больше работы по поиску движка regex. Как таковой, ". * D" фактически гарантирует возврат.

Тем не менее, как насчет:

#! /usr/bin/env python

import re            # regular expressions
import fileinput    # read from STDIN or file

my_regex = '.*Dog.*'
my_matches = 0

for line in fileinput.input():
    line = line.strip()

    if re.search(my_regex, line):
        if my_matches == 0:
            print(line)
        my_matches = my_matches + 1
    else:
        if my_matches != 0:
            print('::::: Pattern %s repeats %i more times.' % (my_regex, my_matches - 1))
        print(line)
        my_matches = 0

Непонятно, что должно происходить с не соседними матчами.

Также не ясно, что должно происходить с однострочными совпадениями, окруженными несоответствующими строками. Добавьте «Doggy» и «Hula» во входной файл, и вы получите соответствующее сообщение «0» больше раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...