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

2024-06-28 11:40:50 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我实际上使用了多个解析器,并在下面的代码中对此进行了说明

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

中全景:

#!/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()

Tags: textinipnonetruemessagereturnif
2条回答

注意:以下代码适用于Python3.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继承的类的实例),然后在message上调用每个实例的parse_sting方法。这个函数不关心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。面向对象的设计使应用程序的流程复杂化,并且您不希望通过提出自己的代码样式或约定而使事情进一步复杂化

如果您希望在增加解析模式的复杂性和数量的同时生成更多python代码,那么至少应该检查正则表达式。一开始它们相当吓人,但是一旦你越过了一点障碍,如果你定期创建代码来匹配模式,它们会极大地提高你的生产力。python标准库中的re module非常易于使用。下面是一个示例代码,它将匹配解析2中的ip地址请求

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

从您的格式看来,您可能有丰富的编程经验,但可能是python新手。如前所述,您应该查看PEP-8 style guide。Python还提供了一些非常棒的特性,这些特性使您可以更轻松地完成您要做的事情。如果您想对许多模式使用regex,并且如果任何模式与当前程序的方式相似,则返回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)

如果您想找个地方快速练习regex语法来掌握它的窍门,try here

相关问题 更多 >