2015-07-18 5 views
1

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

Верно Истина, если данная строка содержит внешний вид «abc», где abc непосредственно не предшествует периоду (.). Так что «qabc» считается, но «r.abc» не учитывается.

Мое решение было:

def abc_there(string): 
    tmp = 0 
    for i in xrange(len(string)): 
     if string[i:i+3] == "abc" and string[i-1] != ".": 
      tmp += 1 
    return tmp > 0 

EDIT:

Просто для уточнения:

".abc" -> False

".abcabc" - -> True

только экземпляр рядом с правом периода стирается.

+0

... Я бы серьезно подумал об использовании [regex] (https: // docs.python.org/2/library/re.html). Но более серьезно, избавиться от tmp, заменить 'tmp + = 1' на' return True' и 'return tmp> 0' с' return False'. Вам нужно только найти одно событие для возврата true. – NightShadeQueen

+0

не обязательно, если строка является «.abcabcabc», она вернет True, так как только первый символ abc сбрасывается – Dividoo

+0

, 'return False' будет находиться вне вашего цикла for и будет работать только в том случае, если' return True' никогда не делал. – NightShadeQueen

ответ

5

Существует менее прямой способ решить эту проблему , и это немного быстрее. Мой код:

def xyz_there(string): 
    return string.count(".abc") != string.count("abc") 

Это работает, потому что если есть строка передается как «abc.abc», «.abc» будет зарегистрировано 1 но абв граф будет 2 Но если строка была например, «fd.abc.abc». Это вернет False.

Чтобы доказать, что это быстрее, я направился к IPython.

In [1]: def abc_there(string): 
...:  tmp = 0 
...:  for i in xrange(len(string)): 
...:   if string[i:i+3] == "abc" and string[i-1] != ".": 
...:    tmp += 1 
...:  return tmp > 0 

In [2]: timeit abc_there("nghkabc") 
Out[2]: 1000000 loops, best of 3: 310 ns per loop 

In [3]: def abc_there(string): 
...:  return string.count(".abc") != string.count("abc") 

In [4]: timeit abc_there("nghkabc") 
Out[4]: 1000000 loops, best of 3: 296 ns per loop 

< 296ns так что мое 310 нс решение было немного быстрее.

+0

Но это быстрее, чем использование регулярного выражения? – martineau

+0

Да, примерно раз 3 Я просто пробовал с решением @piglei и запустил 906ns за цикл –

+0

Если вы хотите, чтобы регулярное выражение выполнялось быстрее в цикле, сделайте следующее: r = re.compile (r "xyz |. * [^.] хуг "); r.match (строка) И положил только часть r.match в цикл –

0
import re 
re.match(r"abc|.*[^.]abc", string) 

или для скорости:

import re 
r = re.compile(r"abc|.*[^.]abc") 
r.match(string) 
r.match(string2) 
+0

Это регулярное выражение кажется слишком сложным, так как вы используете 're.match()'. См. [Обсуждение документации Python на 'search()' vs. 'match()'] (https://docs.python.org/2/library/re.html#search-vs-match). – tsroten

+0

@tsroten re.search regex будет выглядеть так: 'r" [^.] Xyz |^xyz "' Не намного менее сложный, на мой взгляд. Чтобы быть справедливым, решение re.match кажется почти в 3 раза быстрее. –

+0

Да, я думаю, ты прав. Я не понимал, что разница в скорости будет намного лучше использовать match(). – tsroten

5

Регулярные выражения являются идеальным инструментом для этого:

>>> import re 
# Test if it contains a match 
>>> bool(re.search(r'(?:^|[^.])(abc)', 'testabc funcabc')) 
True 
>>> bool(re.search(r'(?:^|[^.])(abc)', '.abc')) 
False 

# Count the number of occurrences 
>>> re.findall(r'(?:^|[^.])(abc)', 'abc testabc func.abc') 
['abc', 'abc'] 
>>> len(re.findall(r'(?:^|[^.])(abc)', 'abc testabc func.abc')) 
2 

Смотрите Python documentation on the re module для более подробной информации.

+0

Возможно, вы захотите переключить порядок своих примеров, так как плакат задал конкретно строку, содержащую '' abc'', и не считая появления. – tsroten

+1

+1 для обеспечения разумного, обобщаемого подхода * с использованием правильных инструментов *, вместо того, чтобы придумывать преждевременный взлом оптимизации, который выдает каждую последнюю наносекунду. – Lynn

+1

Регулярное выражение в этом решении в его текущей форме возвращает false для «abcfsdfdsfdsfsdf». Он не обнаруживает совпадение в начале строки. –

1

Для этого типа регулярных выражений, вероятно, путь. Однако, если вы собираетесь пойти с чем-то вроде того, что у вас уже есть, вы все еще недостаточно ленивы.

def abc_there(string): 
    if string[:3] == "abc": return True #case "abc" at start of string 
    for i in xrange(1,len(string)): 
     if string[i:i+3] == "abc" and string[i-1] != ".": 
      return True #Hah! found something. I get to leave early! 
    #if we make it out of the loop without finding something 
    return False 

Обратите внимание, что если совпадение найдено, вы будете возвращаться True; вы достигаете только return False, если совпадение не найдено. В общем, если вы пишете функцию, которая проверяет что-то в итераторе, вы хотите остановиться и вернуться как можно раньше. (. В any и встроенные функции all разработаны, чтобы сделать это, кстати)

О, я думаю, если вы когда-нибудь проверить что-то в итератора, рассмотреть возможность использования any и all: P

Смежные вопросы