Поиск многословной строки в списке stringsBush Wanderer - код, предназначенный для обученияIncrementing Целые числа в MapDynamic фильтрации и сортировки с базовым классом Entity FrameworkDisposableObject для C # Weekend Challenge - Poker Hand EvaluationEntity Framework Общий шаблон репозиторияКонвертирование между std :: wstring и std :: stringMarkov название страны генераторАсинхронный код обратного вызова в сетиFactor скрипт для изменения случая всех имен файлов в каталогеСохранить и слить номера, как в 2048 game codeToo много циклов в Drawing AppFind min из 3 чисел hardcodedProject Euler # 7 10001st simpleDatabase design для школьной системыСтандартно отклоненный FibonacciLinkedList с помощью реализации узлаMemory с структура twistCustom CursorAdapter DesignEntity с репозиторием и шаблоном Unit of Work и архитектурой POCO Рекурсивная реализация shared_mutexРаспространение большого 1GB-файла со 100-миллионными числами с использованием сортировки слияния. Эти if-утверждения слишком интересны? Случайный IP-адрес GeneratorPI Calculator, Inter view Challenge Генерирование четных случайных чисел Проверка того, является ли число делящимся на 9Password валидации в JavaCounting строк в файле CSV, которые соответствуют строке базы данных, каждая из которых имеет миллион записей. Когда «Актовый вопрос» слишком тонкий. Алгоритм командной строки в C «Полупроводник» mini -programMethod возвращает IEnumerable <T> должны ToList () или notAdvanced и Подробные вероятности мин.

В отличие от Perl, я не могу совместить регулярное выражение внутри оператора if в Python и назначить результат на varaible в тот же момент. Это приводит к типичным конструкциям, подобным этому:

 match = re.search(REGEX, STRING)
if match:
    # do something

До сих пор такой Python. Но что, если я хочу перебирать файл /массив строк, проверять каждую строку на несколько регулярных выражений и запускать catch-all, когда ни один не соответствует? Я не могу думать об этом довольно громоздко и глубоко вложенном if-else-if-else ...- construction:

 import re
strings = ["abc zzz", "y", "#comment"]
for s in strings:
    match = re.search("(\S+) (\S+)", s)
    if match:
        print "Multiword: %s+%s" % (match.group(1), match.group(2))
    else:
        match = re.match("y$", s)
        if match:
            print "Positive"
        else:
            match = re.match("n$", s)
            if match:
                print "Negative"
            else:
                # a few more matches possible in real life script,
                # and then the last catch-all:
                print "No match found, line skipped"

Разве нет способа поставить это в гораздо более привлекательную конструкцию elif или что-то еще? В Python не работает, потому что if-clauses принимают только выражения, а не инструкции. Однако что-то в этом роде могло бы поразить меня как питона, или я не вижу ничего очевидного здесь?

 if match = re.search(" ", s):
    print "Multiword: %s+%s" % (match.group(1), match.group(2))
elif match = re.match("y$", s):
    print "Positive"
else:
    print "No match found, line skipped"
0 голосов | спросил Toby AdamsKaoKristof ClaesNathanaelSimon Forsberga 26 FebruaryEurope/MoscowbFri, 26 Feb 2016 17:59:00 +0300000000pmFri, 26 Feb 2016 17:59:00 +030016 2016, 17:59:00

9 ответов


28

Просто используйте ключевое слово continue, чтобы заставить продвижение оценивать следующую строку. Код после оператора if будет выполняться только в том случае, если предыдущий оператор был ложным.

import re
strings = ["abc zzz", "y", "#comment"]
for s in strings:
    match = re.search("(\S+) (\S+)", s)
    if match:
        print "Multiword: %s+%s" % (match.group(1), match.group(2))
        continue
    match = re.match("y$", s)
    if match:
        print "Positive"
        continue
    match = re.match("n$", s)
    if match:
        print "Negative"
        continue

    # a few more matches possible in real life script,
    # and then the last catch-all:
    print "No match found, line skipped"
ответил flakes 24 MarpmMon, 24 Mar 2014 19:03:58 +04002014-03-24T19:03:58+04:0007 2014, 19:03:58
14

Почему бы не использовать список кортежей (re, lambda match: action), что-то вроде

actions = [("(\S+) (\S+)", lambda match: "Multiword: %s+%s" % (match.group(1), match.group(2))),
           ("y$", lambda match: "Positive"),
           ("n$", lambda match: "Negative")]

, а затем:

for rex, action in actions:
     match = re.match(rex, s)
     if match: 
          print action(match)

Если вам нужно смешать поиск и совпадение, вы можете использовать список кортежей:

(matchmethod, rex, action)

, как в

actions = [
    (re.search, "(\S+) (\S+)", lambda match: "Multiword: %s+%s"%(match.group(1), match.group(2)) ),
    (re.match, "y$", lambda match: "Positive"),
    (re.match, "n$", lambda match: "Negative")]

И, конечно же:

for matchtype, rex, action in actions:
     match = matchtype(rex, s)
     if match: 
          print action(match)
ответил hivert 24 MarpmMon, 24 Mar 2014 19:00:07 +04002014-03-24T19:00:07+04:0007 2014, 19:00:07
12

Я бы поместил его в функцию и return из него, когда совпадение было найдено, так что у вас нет всех отступов для случаев else: , просто список тестов и возвращает для них:

import re
strings = ["abc zzz", "y", "#comment"]

def run_tests(s)
    match = re.search("(\S+) (\S+)", s)
    if match:
        print "Multiword: %s+%s" % (match.group(1), match.group(2))
        return

    if re.match("y$", s):
        print "Positive"
        return

    if re.match("n$", s):
        print "Negative"
        return

    # a few more matches possible in real life script,
    # and then the last catch-all:
    print "No match found, line skipped"

for s in strings:
    run_tests(s)

Я бы постарался перечислить список тестов в некоторую структуру данных (например, сообщения и шаблоны для тестирования), но поскольку код немного отличается (поиск по совпадению, простое копирование и выполнение чего-то с совпадение), это ясно, чтобы сохранить его таким образом.

ответил RemcoGerlich 24 MarpmMon, 24 Mar 2014 19:03:29 +04002014-03-24T19:03:29+04:0007 2014, 19:03:29
6

Мне нравится подход @ hivert, но он будет формализовать его немного больше:

import re

tests = [
    ("(\S+) (\S+)", "Multiword: {0}+{1}"),
    ("^y$",         "Positive"),
    ("^n$",         "Negative")
]

def get_first_match(s, tests=tests, none_match="No match found, line skipped"):
    for reg,fmt in tests:
        match = re.search(reg, s)
        if match:
            return fmt.format(*match.groups())
    return none_match

затем

strings = ["abc zzz", "y", "#comment"]
for s in strings:
    print(get_first_match(s))
ответил Hugh Bothwell 24 MarpmMon, 24 Mar 2014 19:09:43 +04002014-03-24T19:09:43+04:0007 2014, 19:09:43
5

Это известная проблема с регулярными выражениями. Но вы можете просто поместить параметры в контейнер, например список, а затем использовать цикл for:

import re
strings = ["abc zzz", "y", "#comment"]
regexps_and_messages = [
    ("(\S+) (\S+)", "Multiword: %s+%s"),
    ("y$", "Positive"),
    ("n$", "Negative"),
]

for s in strings:
    for regexp, message in regexps_and_messages:
        m = re.match(regexp, s)
        if m is not None:
            print message % m.groups()
            break
    else: # if no break in above loop
        print "No match found, line skipped"
ответил taleinat 24 MarpmMon, 24 Mar 2014 19:03:47 +04002014-03-24T19:03:47+04:0007 2014, 19:03:47
5

Чтобы пойти еще дальше на подходы, предлагающие добавить регулярные выражения в список, вы можете присоединиться к регулярным выражениям вместе с | а затем сопоставить линию со всеми возможными шаблонами за один раз.

import re

class LineMatcher(object):
    def __init__(self, patterns):
        # In order to match each string, we build a regex combining which can match
        # all the parts. 
        # Something like: ((\S+) (\S+))|(y$)|(n$)|(.*))
        # When we match against it, we can figure out which pattern was matched
        self._groups = {}
        regexes = []

        # because groups could contain groups, we need to keep track of the current
        # group index so that we know which index each pattern will end up with.
        current_group_index = 1
        for pattern, handler in patterns:
            group_count = re.compile(pattern).groups
            self._groups[current_group_index] = (group_count, handler)
            regexes.append("(%s)" % pattern)
            current_group_index += group_count + 1

        self._regex = re.compile("|".join(regexes))

    def match(self, string):
        match = self._regex.match(string)
        group_count, handler = self._groups[match.lastindex]
        captures = match.groups()[match.lastindex:match.lastindex + group_count]
        return handler(*captures)


matcher = LineMatcher([
    ("(\S+) (\S+)", lambda first, second: "Multiword: %s+%s"),
    ("y$", lambda: "Positive"),
    ("n$", lambda: "Negative"),
    (".*", lambda: "No match found, line skipped")
])


strings = ["abc zzz", "y", "#comment"]
for s in strings:
    print matcher.match(s)
ответил Winston Ewert 24 MarpmMon, 24 Mar 2014 19:40:19 +04002014-03-24T19:40:19+04:0007 2014, 19:40:19
5

ответ Калпратта без continue:

import re
strings = ["abc zzz", "y", "#comment"]
for s in strings:
    match = re.search("(\S+) (\S+)", s)
    if match:
        print "Multiword: %s+%s" % (match.group(1), match.group(2))
    elif re.match("y$", s):
        print "Positive"
    elif re.match("n$", s):
        print "Negative"
    else:
        print "No match found, line skipped"
ответил Cees Timmerman 24 MarpmMon, 24 Mar 2014 21:41:23 +04002014-03-24T21:41:23+04:0009 2014, 21:41:23
3

Как только вы узнали шаблон в своем коде, вы можете обернуть его как базовый класс, чтобы избежать шаблонов. Это также делает код более удобным.

import re

class Handler:
    PATTERN = ''
    def __init__(self):
        self._pattern = re.compile(self.PATTERN)

    def match(self, *args, **kwargs):
        return self._pattern.match(*args, **kwargs)

    def handle(self, matched):
        pass

class MultiwordHandler(Handler):
    PATTERN = '(\S+) (\S+)'

    def match(self, *args, **kwargs):
        return self._pattern.search(*args, **kwargs)

    def handle(self, matched):
        print 'Multiword: %s+%s' % (matched.group(1), matched.group(2))

class PositiveHandler(Handler):
    PATTERN = 'y$'

    def handle(self, matched):
        print 'Positive'

class NegativeHandler(Handler):
    PATTERN = 'n$'

    def handle(self, matched):
        print 'Negative'

И используйте их следующим образом:

handlers = [MultiwordHandler(), PositiveHandler(), NegativeHandler()]

strings = ["abc zzz", "y", "#comment"]

for s in strings:
    for handler in handlers:
        matched = handler.match(s)
        if matched:
            handler.handle(matched)
            break
    else:
        print "No match found, line skipped"
ответил Ray 26 MarpmWed, 26 Mar 2014 14:01:18 +04002014-03-26T14:01:18+04:0002 2014, 14:01:18
-2

Вы можете сделать поток вашего приложения более линейным с помощью return -ing из метода при сбое или сделать это Python way с помощью Exceptions , например:

try:
    if not do_action_1:
        raise Exception('Action 1 failed')
    if not do_action_2:
        raise Exception('Action 2 failed')
    if not do_action_3:
        raise Exception('Action 3 failed')
    if not do_action_4:
        raise Exception('Action 4 failed')
    if not do_action_5:
        raise Exception('Action 5 failed')
except Exception as e:
    print 'Whoops: %s' % e
ответил Andrew Dunai 24 MarpmMon, 24 Mar 2014 18:50:16 +04002014-03-24T18:50:16+04:0006 2014, 18:50:16

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132