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

如何生成高效优化的HH:MM格式正则表达式以过滤日志时间?

问题

给定两个HH:MM格式的时间,需要过滤出包含这两个时间之间所有时刻的日志。例如给定09:30和15:30,可以用简化正则T(09:[345]|1[01234]|15:[123])(假设输入格式合法)。当前用Python代码生成枚举所有时刻的正则(如T(09:30|09:31|.....|15:30)),想咨询:

  1. 如何生成更高效的正则?
  2. 枚举式正则是否比优化后的正则处理速度更快?
    最终将在Go正则引擎中使用该正则,也可接受Unix工具方案。

当前使用的Python代码如下:

from dataclasses import dataclass
import datetime
import re

@dataclass
class TimeFilter:
   start: datetime.time
   stop: datetime.time

   def timergx(self):
     i = self.start.hour * 60 + self.start.minute
     stop = self.stop.hour * 60 + self.stop.minute
     return "T(" + "|".join(f"{x // 60:02d}:{x % 60:02d}" for x in range(i, stop)) + ")"

def HHMM2time(txt: str):
    return datetime.time(*[int(x) for x in txt.split(":")])

tf = TimeFilter(HHMM2time("9:30"), HHMM2time("15:30"))
assert re.match(tf.timergx(), "T10:30")

一、生成高效正则的方法

要生成紧凑高效的正则,需将时间范围拆分为起始小时的剩余分钟段、中间完整小时段、结束小时的开头分钟段三部分处理,通过字符范围匹配减少分支数量:

实现代码

from dataclasses import dataclass
import datetime

@dataclass
class TimeFilter:
    start: datetime.time
    stop: datetime.time

    def timergx(self):
        parts = []
        start_hour, start_min = self.start.hour, self.start.minute
        stop_hour, stop_min = self.stop.hour, self.stop.minute

        # 处理起始小时的剩余分钟
        if start_min < 60 and start_min != 0:
            min_part = self._get_minute_range_re(start_min, 59)
            parts.append(f"{start_hour:02d}:{min_part}")

        # 处理中间完整小时
        if start_hour + 1 < stop_hour:
            if start_hour +1 == stop_hour -1:
                parts.append(f"{start_hour+1:02d}:[0-5][0-9]")
            else:
                parts.append(f"{start_hour+1:02d}[{start_hour+2}-{stop_hour-1}]:[0-5][0-9]".replace("-", ""))

        # 处理结束小时的分钟
        if stop_hour > start_hour:
            if stop_min != 0:
                min_part = self._get_minute_range_re(0, stop_min)
                parts.append(f"{stop_hour:02d}:{min_part}")
        elif stop_hour == start_hour:
            min_part = self._get_minute_range_re(start_min, stop_min)
            parts.append(f"{start_hour:02d}:{min_part}")

        return f"T({'|'.join(parts)})"

    def _get_minute_range_re(self, start, end):
        # 生成分钟范围的正则表达式
        if start == end:
            return f"{start:02d}"
        ranges = []
        current_start = start
        for m in range(start, end+1):
            if m == end or (m //10) != ((m+1)//10):
                if current_start == m:
                    ranges.append(f"{current_start:02d}")
                else:
                    tens_current = current_start //10
                    ones_current = current_start %10
                    tens_m = m //10
                    ones_m = m %10
                    if tens_current == tens_m:
                        ranges.append(f"{tens_current}[{ones_current}-{ones_m}]")
                    else:
                        ranges.append(f"{tens_current}[{ones_current}-9]|{tens_m}[0-{ones_m}]")
                current_start = m+1
        return "|".join(ranges)

def HHMM2time(txt: str):
    return datetime.time(*[int(x) for x in txt.split(":")])

tf = TimeFilter(HHMM2time("9:30"), HHMM2time("15:30"))
print(tf.timergx())
# 输出:T(09:[3-5][0-9]|1[0-4]:[0-5][0-9]|15:[0-2][0-9]|15:30)

二、性能对比:枚举式 vs 优化正则

在Go的RE2正则引擎中,优化后的紧凑正则速度更快,原因如下:

  • 枚举式正则会生成大量分支(比如09:30到15:30对应361个分支),RE2处理多分支时需要逐个匹配,分支越多耗时越长。
  • 紧凑正则通过字符范围匹配将分支压缩到个位数(示例仅4个分支),引擎可以快速完成范围判断。
  • 枚举式正则字符串长度远大于紧凑正则,加载和解析的开销也更高。

仅当时间范围极小(比如仅几个时刻)时,两者差异可忽略;范围超过10个时刻后,紧凑正则的优势会明显显现。

三、Unix工具替代方案

如果不需要用正则,Unix环境下用awk直接解析时间做数值比较,效率比正则更高:

# 假设日志每行包含类似"T09:30"的时间字段,提取后判断
awk -v start="09:30" -v stop="15:30" '
function time2min(t) {
    split(t, hhmm, ":");
    return hhmm[1]*60 + hhmm[2];
}
{
    # 提取时间部分(假设时间在字符串开头,格式为"T09:30...")
    t = substr($0, 2, 5);
    if (time2min(t) >= time2min(start) && time2min(t) <= time2min(stop)) print;
}' logfile.txt

这种方法直接将时间转为分钟数做数值对比,逻辑直观,处理大日志文件时性能更稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 17:47:25