如何构造字符串中的关键字的多个解析器?

时间:2017-08-14 14:48:44

标签: python parsing boolean

我正在编写一些解析字符串的代码,通常使用简单的关键字。在解析时,代码执行各种操作,例如打印响应,运行函数等,并跟踪它是否能够响应。

我实际上正在使用多个解析器,并在下面的代码中说明了这一点。

构建此代码的更好方法是什么,特别是考虑到可伸缩性和代码紧凑性?例如,假设添加了更多解析器,这些解析器的操作原理比简单的关键字定位更复杂。

MWE:

#!/usr/bin/python

import json
import os
import requests
import subprocess
import sys

def main():

    message = "how are you"
    #message = "ip address"
    #message = "restart"

    triggered = [
        parse_1(message = message),
        parse_2(message = message)
    ]

    if not any(triggered):

        report_help()

def parse_1(
    message = None
    ):

    def keyphrases_text_response(
        message    = None,
        keyphrases = None,
        response   = None
        ):

        if any(pattern in message for pattern in keyphrases):

            print(response)

            return True

        else:

            return False

    triggered = [
        keyphrases_text_response(
            message    = message,
            keyphrases = [
                        "image"
                        ],
            response   = "http://i.imgur.com/MiqrlTh.jpg"
        ),
        keyphrases_text_response(
            message    = message,
            keyphrases = [
                        "sup",
                        "hi"
                        ],
            response   = "sup home bean"
        ),
        keyphrases_text_response(
            message    = message,
            keyphrases = [
                        "how are you",
                        "are you well",
                        "status"
                        ],
            response   = "nae bad fam"
        ),
        keyphrases_text_response(
            message    = message,
            keyphrases = [
                        "help",
                        "what can you do"
                        ],
            response   = "I can report my IP address and I can restart my script."
        )
    ]

    if any(triggered):

        return True

    else:

        return False

def parse_2(
    message = None
    ):

    triggered = []

    if any(pattern in message for pattern in\
        [
            "IP",
            "I.P.",
            "IP address",
            "I.P. address",
            "ip address"
        ]
        ):

        triggered.append(True)
        report_IP()

    if any(pattern in message for pattern in\
        [
            "restart"
        ]
        ):

        triggered.append(True)
        restart()

    if any(pattern in message for pattern in\
        [
            "SSH",
            "reverse"
        ]
        ):

        triggered.append(True)
        engage_command(
            command    = "ssh -R 10000:localhost:22 www.sern.ch",
            background = True
        )

    if any(triggered):

        return True

    else:

        return False

def report_IP(
    contact = None,
    country = True
    ):

    IP = "unknown"

    try:

        data_IP_website = requests.get("http://ipinfo.io/json")
        data_IP         = data_IP_website.json()
        IP              = data_IP["ip"]
        country         = data_IP["country"]

    except:

        pass

    text = "IP address: " + IP

    if country:

        text = text + " (" + country + ")"

    print(text)

def restart():

    print("restart! (and I'm in a crazy loop!)")
    import __main__
    os.execv(__main__.__file__, sys.argv)

def report_help():

    print("I can report my IP address, I can restart my script and I can run commands.")

def engage_command(
    command    = None,
    background = False
    ):

    print("engage command: {command}".format(command = command))

    if not background:

        process = subprocess.Popen(
            [command],
            shell      = True,
            executable = "/bin/bash"
        )
        process.wait()
        output, errors = process.communicate()

        return output

    else:

        subprocess.Popen(
            [command],
            shell      = True,
            executable = "/bin/bash"
        )

        return None

if __name__ == "__main__":

    main()

2 个答案:

答案 0 :(得分:0)

注意:以下代码适用于Python 3.5或更高版本 首先,您将解析器的逻辑与通过解析器运行字符串的代码的逻辑分开。让我们从后者的代码开始:

from typing import List


def run_parsers(message: str, parsers: List[BaseParser]) -> None:
    for parser in parsers:
        parser.parse_message(message)

注意:在最新的Python版本中,您可以注释代码。我在这里选择这样做的原因是为了清楚地说明这个函数并不关心它获得的解析器的“类型”。它需要一个BaseParser个实例列表(包括继承自BaseParser的类的实例),然后在parse_sting上调用每个实例的message方法。此功能不关心parse_message的作用 接下来,您要为解析器对象定义API,以便run_parsers可以在不知道它们如何工作的情况下使用它们。

class BaseParser:
    def __init__(self):
        self.triggered = False

    def parse_message(self, message: str):
        raise NotImplementedError

正如您所看到的,BaseParser几乎没有逻辑,它只是说继承自我的人应该定义parse_message。此外,继承者获得triggered属性 现在,让我们看一个这样的继承者的代码。

class ImageParser:

    def __init__(self):
        super().__init__()
        self.key_phrases = ('jpg', 'png')

    def parse_message(self, message):
        for phrase in self.key_phrases:
            if phrase in message:
                self.respond()
                self.triggered = True

    def respond(self):
        do_something_here()

只要继承者遵循BaseInheriter设置的“规则”(即实现方法并具有名为triggered的属性),run_parsers将很乐意运行它们。
注意:ImageParsertriggered设置为True,这就是确定哪些解析器采取某些操作的方法。
最后,让我们转换您的main函数,使其与上面的代码一起使用:

def main():
    message = 'how  are you?'
    parsers = [ImageParser(), IPParser()]
    run_parsers(message, parsers)
    if not any([parser.triggered for parser in parsers]):
        show_help()

重要提示:请务必阅读并使用pep8 guidelines。面向对象的设计使应用程序的流程变得复杂,您不希望通过提出自己的代码样式或约定来进一步使事情复杂化。

答案 1 :(得分:0)

如果您希望制作更多pythonic代码,同时增加解析模式的复杂性和数量,那么您至少应该检查正则表达式。它们起初非常令人生畏,但是如果你创建代码以定期匹配模式,那么一旦你越过山坡,他们就会大大提高你的工作效率。 python标准库中的re module非常简单易用。下面是示例代码,它将匹配parse_2中的IP地址请求。

import re
message = 'ip address'
if re.match(r'[iI]\.*[pP]\.*', message):
    report_IP()

从你的格式化看起来很明显你可能有很多编程经验,但可能是python的新手。如前所述,您应该查看PEP-8 style guide。 Python还附带了一些很棒的功能,可以让你做的事情变得更容易。如果你想在很多模式中使用正则表达式,并且如果有任何匹配方式与当前程序类似,则返回True,你可能想要这样做:

import re

def print_username(string): print string
def print_password(string): print string
def print_hex(string): print string

triggers = [
    (r'^[a-z0-9_-]{3,16}$', print_username),
    (r'^[a-z0-9_-]{6,18}$', print_password),
    (r'^#?([a-f0-9]{6}|[a-f0-9]{3})$', print_hex)]

def handle_message(message = None):
    if not message: return(False)
    else:
        any_triggered = False
        for trigger in triggers:
            if re.match(trigger[0], message):
                any_triggered = True
                trigger[1](message)
        return(any_triggered)

如果你想在某个地方快速练习正则表达式语法来获取它,try here