You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

网站Bot框架开发:如何优化正则表达式多匹配逻辑?

问题描述

我正在为某网站开发首个Bot框架,目前编写了一个接收用户消息的类。网站消息分为两类:用户消息和系统消息,系统消息有20种左右(比如新订单、新评价、评价删除等)。

关键限制:所有消息在HTML层面完全一致,无法通过解析HTML区分消息类型,只能通过消息文本判断。

我现在给消息对象加了message_type属性,实现方式是写20个正则表达式,处理每条消息时循环遍历这些正则,找到能full_match()的项就返回对应的类型,否则判定为用户消息。想知道有没有优化这个流程的方法。

补充说明:只能获取消息文本,HTML层面无任何区分依据,用户也无法区分系统消息和普通消息(相关疑问请咨询网站开发者)。

系统消息示例:

  • 新订单:User X paid for order number 12321.
  • 新评价:User X left a review for order number 12321.
  • 纠纷发起:User X opened a dispute on order number 12321.
  • 纠纷关闭:Administrator X has closed the dispute for order number 12321.
  • 部分退款:Administrator X refunded some funds to customer Y for order number 12321.

当前实现代码:

from enum import Enum
import re

class MessageType(Enum):
    """所有系统消息类型的枚举"""
    NEW_ORDER = 1
    NEW_REVIEW = 2
    DISPUTE_OPENED = 3
    DISPUTE_CLOSED = 4
    PARTIAL_REFUND = 5
    
    USER_MESSAGE = 0


# 消息类型对应的正则表达式映射
message_type_re = {
    MessageType.NEW_ORDER: re.compile(r"User [a-zA-Z0-9]+ paid for order number [0-9]{5}\.") ,
    MessageType.NEW_REVIEW: re.compile(r"User [a-zA-Z0-9]+ left a review for order number [0-9]{5}\.") ,
    MessageType.DISPUTE_OPENED: re.compile(r"User [a-zA-Z0-9]+ opened a dispute on order number [0-9]{5}\.") ,
    MessageType.DISPUTE_CLOSED: re.compile(r"Administrator [a-zA-Z0-9]+ closed the dispute for order number [0-9]{5}\.") ,
    MessageType.PARTIAL_REFUND: re.compile(r"Administrator [a-zA-Z0-9]+ refunded some funds to customer [a-zA-Z0-9]+ for order number [0-9]{5}\.")
}


class Message:
    """消息对象"""
    def __init__(self, text: str, *args):
        self.text: str = text
        """消息文本内容"""

        self.type = self.determine_message_type()
        """消息类型"""

    def determine_message_type(self) -> MessageType:
        """判断消息类型的方法"""
        for message_type in message_type_re:
            if message_type_re[message_type].fullmatch(self.text):
                return message_type
        return MessageType.USER_MESSAGE
优化方案

1. 合并正则表达式,一次匹配完成判断

把所有系统消息的正则合并成一个大正则,通过命名分组区分不同类型,只需一次匹配就能完成判断,避免循环遍历多个正则,效率最高。

示例代码:

from enum import Enum
import re

class MessageType(Enum):
    NEW_ORDER = 1
    NEW_REVIEW = 2
    DISPUTE_OPENED = 3
    DISPUTE_CLOSED = 4
    PARTIAL_REFUND = 5
    USER_MESSAGE = 0

# 合并所有系统消息正则,用命名分组标记类型
combined_re = re.compile(
    r"(?P<new_order>User [a-zA-Z0-9]+ paid for order number [0-9]{5}\.)|"
    r"(?P<new_review>User [a-zA-Z0-9]+ left a review for order number [0-9]{5}\.)|"
    r"(?P<dispute_opened>User [a-zA-Z0-9]+ opened a dispute on order number [0-9]{5}\.)|"
    r"(?P<dispute_closed>Administrator [a-zA-Z0-9]+ closed the dispute for order number [0-9]{5}\.)|"
    r"(?P<partial_refund>Administrator [a-zA-Z0-9]+ refunded some funds to customer [a-zA-Z0-9]+ for order number [0-9]{5}\.)"
)

# 分组名到MessageType的映射
group_to_type = {
    "new_order": MessageType.NEW_ORDER,
    "new_review": MessageType.NEW_REVIEW,
    "dispute_opened": MessageType.DISPUTE_OPENED,
    "dispute_closed": MessageType.DISPUTE_CLOSED,
    "partial_refund": MessageType.PARTIAL_REFUND
}

class Message:
    def __init__(self, text: str, *args):
        self.text = text
        self.type = self.determine_message_type()

    def determine_message_type(self) -> MessageType:
        match = combined_re.fullmatch(self.text)
        if match:
            # 遍历分组找到匹配的类型
            for group_name, msg_type in group_to_type.items():
                if match.group(group_name):
                    return msg_type
        return MessageType.USER_MESSAGE

2. 按特征排序正则,减少平均匹配次数

如果某些系统消息出现频率更高,或者特征更独特(比如开头是Administrator和User的可以分组),可以把这类正则放在遍历顺序的前面,减少平均需要匹配的正则数量。

示例调整:

# 按开头特征分组排序,先处理Administrator开头的消息
message_type_re = [
    (MessageType.DISPUTE_CLOSED, re.compile(r"Administrator [a-zA-Z0-9]+ closed the dispute for order number [0-9]{5}\.")),
    (MessageType.PARTIAL_REFUND, re.compile(r"Administrator [a-zA-Z0-9]+ refunded some funds to customer [a-zA-Z0-9]+ for order number [0-9]{5}\.")),
    (MessageType.NEW_ORDER, re.compile(r"User [a-zA-Z0-9]+ paid for order number [0-9]{5}\.")),
    (MessageType.NEW_REVIEW, re.compile(r"User [a-zA-Z0-9]+ left a review for order number [0-9]{5}\.")),
    (MessageType.DISPUTE_OPENED, re.compile(r"User [a-zA-Z0-9]+ opened a dispute on order number [0-9]{5}\."))
]

class Message:
    # 其他代码不变
    def determine_message_type(self) -> MessageType:
        for message_type, pattern in message_type_re:
            if pattern.fullmatch(self.text):
                return message_type
        return MessageType.USER_MESSAGE

3. 保留预编译正则(已实现)

你当前代码中已经提前编译了所有正则,这是基础优化点,避免每次匹配都重新编译正则,建议继续保留。

总结
  • 优先选择合并正则表达式的方案,一次匹配完成判断,效率最优;
  • 如果合并后正则可读性下降,可以用按特征排序正则的方案,降低平均匹配次数;
  • 20种类型的场景下,前两种方案完全够用,无需引入复杂的前缀树等实现。

内容的提问来源于stack exchange,提问作者Gygabrain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 13:57:34