【问题标题】:Regex Expression to capture repeated patterns正则表达式捕获重复模式
【发布时间】:2017-09-13 20:16:01
【问题描述】:

我一直在互联网上四处奔波,试图找出如何构建正则表达式来以我需要的方式捕获文本;所以我看到了一些 StackOverflow 问题,但没有一个能表达我想要的,但如果你已经在这里看到了与我的问题类似的东西,请随意指向那篇文章......

我尝试使用递归,但似乎我还不够好,无法让某些东西发挥作用

一些注意事项:

1) 我不能使用解析程序,因为将使用这些数据的程序将使用正则表达式来捕获它,而这个程序是一个“通用”程序,实际上它正在捕获任何需要的数据,我唯一需要做的就是给出正确的正则表达式来获取它需要的信息,而且我需要尽可能地保持它的一致性,所以我不能使用第三方或外部程序。

2) 对 'key': 'value' 可能会有所不同,它们的对数并不总是相同......这就是我认为的困难所在。

3) 将使用此正则表达式的程序是在 Python 2.7.3 中创建的: 这个程序是如何工作的: 它使用一个 Json 配置文件,我可以在其中设置要运行的命令,该命令将为我提供所需的数据,然后我指定一个正则表达式来教程序需要捕获什么以及如何处理它,即:如何处理被捕获的组......所以这就是我不能使用解析器的原因。 该程序使用结构将配置的收集器(使用正则表达式)运行到远程主机并收集所有数据...

4) 程序用于收集数据以将它们发布到网络服务器并获取指标和其他内容,例如图表和监控警报等

我已经能够捕获我计划捕获的几乎所有数据,但是当我试图为此创建一个收集器时,我被卡住了..

以下数据重复如下,但服务器名称不同,当然值也会改变:

Server: Omega-X
celery.queue_length: {'transfer_data': '0', 'factor_a': '0', 'slow': '0', 'factor_b': '0', 'score_retry': '0', 'damage_factor_c': '0', 'voice_ud': '0', 'alarm_factors_bl': '0', 'telemetry_x': '0', 'endstream': '0', 'celery': '0', 'awl': '0', 'prs': '0', 'score': '0', 'feature_factors_xf': '0', 'feature_factors_dc': '0'}


Server: Alfa-X
celery.queue_length: {'transfer_data': '0', 'factor_a': '0', 'slow': '0', 'factor_b': '0', 'score_retry': '0', 'damage_factor_c': '0', 'voice_ud': '0', 'alarm_factors_bl': '0', 'telemetry_x': '0', 'endstream': '0', 'celery': '0', 'awl': '0', 'prs': '0', 'score': '0', 'feature_factors_xf': '0', 'feature_factors_dc': '0'}

我想如何捕捉它:

Server: Omega-X

 transfer_data: 0
 factor_a: 0
 slow: 0
 factor_b: 0
 score_retry: 0
 damage_factor_c: 0
 voice_ud: 0
 alarm_factors_bl: 0
 telemetry_x: 0
 endstream: 0
 celery: 0
 awl: 0
 trx: 0
 points: 0
 feature_factors_xf: 0
 feature_factors_dc: 0

Server: Alfa-X

 transfer_data: 0
 factor_a: 0
 slow: 0
 factor_b: 0
 score_retry: 0
 damage_factor_c: 0
 voice_ud: 0
 alarm_factors_bl: 0
 telemetry_x: 0
 endstream: 0
 celery: 0
 awl: 0
 trx: 0
 points: 0
 feature_factors_xf: 0
 feature_factors_dc: 0

如果显示一个唯一的服务器,那么并不难,使用下面的正则表达式我可以捕获所有(服务器名称除外):

'([a-z_]+)':\s'(\d+)'

这个正则表达式将只给出第二部分,即变量和值的列表,而不是服务器名称......所以如果我在相同的输出上获得几个具有相同数据的服务器,那么将无法从值来自哪个服务器...

如果我尝试添加对服务器名称的支持: 我尝试了以下正则表达式,它可以工作,但只能捕获服务器名称和第一对参数:

Server:\s([a-zA-Z0-9-]+)\s*celery\.queue_length:\s.('([a-z_]+)':\s'(\d+)')*

我尝试了多种递归功能,但未能实现我想要的。

谁能给我指出正确的方向...?

谢谢。

【问题讨论】:

  • 您的第一个模式有效,因为它一次匹配每个键/值对。听起来您现在要做的是一次性处理整个集合,只需一个正则表达式模式。让你的程序像这样捕获任意数量的组可能是不可能的(但如果数量相同,那也不会那么糟糕,正如你上面提到的那样)。与其专注于捕获键/值数据,您可以通过格式化操作(例如匹配celery\.queue_length: \{|, 并替换为\n)来解决问题吗?见:regex101.com/r/rzmJgj/1
  • 您好 CAustin,感谢您的回复。它可能很有用,但仍然需要像你提到的那样进行一些清洁。睡觉后,我开始想你和其他人可能会提到,仅使用正则表达式几乎不可能实现,因为我也需要捕获组......
  • 我不得不承认我需要在这里违反自己的规则,因为我想要的程序使用正则表达式很难实现。我的意思是;我的程序需要有组才能收集数据,所以在这种情况下使用正则表达式它会给我n个我可能无法正确处理的组......所以可能需要一个预解析程序...

标签: python regex regex-recursion


【解决方案1】:

你想要键值?用蟒蛇 我会用字典。

  1. 获取服务器名称和包含数据的字符串:
    Server: ([^\n]*)(?:[^{]*)\{(.*)\}

  2. 用包含每个服务器数据的字符串构建一个字典:

用python(只需要import re语句):

input = """Server: Omega-X
celery.queue_length: {'transfer_data': '0', 'factor_a': '0', 'slow': '0', 'factor_b': '0', 'score_retry': '0', 'damage_factor_c': '0', 'voice_ud': '0', 'alarm_factors_bl': '0', 'telemetry_x': '0', 'endstream': '0', 'celery': '0', 'awl': '0', 'prs': '0', 'score': '0', 'feature_factors_xf': '0', 'feature_factors_dc': '0'}

Server: Alfa-X
celery.queue_length: {'transfer_data': '0', 'factor_a': '0', 'slow': '0', 'factor_b': '0', 'score_retry': '0', 'damage_factor_c': '0', 'voice_ud': '0', 'alarm_factors_bl': '0', 'telemetry_x': '0', 'endstream': '0', 'celery': '0', 'awl': '0', 'prs': '0', 'score': '0', 'feature_factors_xf': '0', 'feature_factors_dc': '0'}"""


for match in re.findall(r'Server: ([^\n]*)(?:[^{]*)\{(.*)\}', input):
    server = match[0]
    data = match[1]
    datadict = dict((k.strip().replace("'", ""), v.strip().replace("'", "")) for k,v in (item.split(':') for item in data.split(',')))
    datadict['serveur'] = server

然后您可以存储每个数据字典(例如,在列表中)并根据需要使用 then。您可以将值从字符串转换为整数以轻松操作它们。

【讨论】:

  • 对不起,mquantin,在这里发布我的其他想法之前没有看到你的答案,我也会检查你的建议,谢谢!
  • 嗨,mquantin,你知道吗,我喜欢这个,因为它可以在不改变我认为更好的原始格式的情况下捕获所有内容......我避免进入收集器的 python 代码仅针对此特定输出执行此操作,但我认为没有其他简单的方法可以获取它...非常感谢,我想我会使用这种方法。
【解决方案2】:

您可以使用 Antlr 来定义您的语法,这将是比正则表达式更好的选择:https://dzone.com/articles/antlr-4-with-python-2-detailed-example

如果你想使用正则表达式,你可以使用下面的代码,请注意我的代码是用 C# 编写的,但是正则表达式在 Python 中的行为应该是一样的。

string serverNamePattern = @"(?<=Server(\s)*:(\s))\s*[\w-]+";
string dataPattern = @"(?<=celery.queue_length[\s:]*{)[a-zA-Z0-9\s:\'_,]+";
string input = 
    "Server: Omega-X" + 
    "celery.queue_length: {'transfer_data': '0', 'factor_a': '0', 'slow': '0', 'factor_b': '0', 'score_retry': '0', 'damage_factor_c': '0', 'voice_ud': '0', 'alarm_factors_bl': '0', 'telemetry_x': '0', 'endstream': '0', 'celery': '0', 'awl': '0', 'prs': '0', 'score': '0', 'feature_factors_xf': '0', 'feature_factors_dc': '0'}" + 
    "Server: Alfa-X" + 
    "celery.queue_length: {'transfer_data': '0', 'factor_a': '0', 'slow': '0', 'factor_b': '0', 'score_retry': '0', 'damage_factor_c': '0', 'voice_ud': '0', 'alarm_factors_bl': '0', 'telemetry_x': '0', 'endstream': '0', 'celery': '0', 'awl': '0', 'prs': '0', 'score': '0', 'feature_factors_xf': '0', 'feature_factors_dc': '0'}";

var serverNames = Regex.Matches(input, serverNamePattern);
var dataMatches = Regex.Matches(input, dataPattern);

解释:

+:出现一次或多次

\w: 字母数字

\s: 空格

[]:定义范围

(?

(?:(\s))\s[\w-]+:匹配字母数字,- 和 Server 后面的空格:

(?,]+: 匹配 [a-zA-Z0-9 ':,\s] 后跟在 celery.queue_length:

请注意,您需要在服务器名称前添加“服务器:”。这也不会从数据中删除单引号。

【讨论】:

  • 嗨,Hooman,我了解您的方法,但不确定是否可以将其应用于我拥有的程序。它可能会改变其他有效指标的行为,但尽管如此,我可以尝试...可能我需要一个新的观点...谢谢!
  • 对不起,我没有放正确的代码,更新了。请注意,Matches 返回一个可以迭代的匹配列表,因此正则表达式和匹配组没有问题......但我认为 Antlr 是复杂语法的更好选择。
  • 嗨,Hooman,再想一想,将需要一个预解析器程序(是的,我知道我会在这里反对自己),以按照我的意愿准备输出......
【解决方案3】:

感谢热心回答我问题的人,我想你们都帮助我重塑了我看待这个问题的方式......

我相信,我想在这里实现的对于正则表达式来说非常困难:

给出如何获取我想要的信息的难度。我在想以哪种方式更容易获得这些信息。所以我知道我在这里违反了自己的规则,但我认为没有其他方法可以顺利进行。

如果我想得到像这样的正则表达式组:

Server: Group 0
Key : Group 1
Value: Group 2

那么我需要的输出应该是:

Regex Groups:
        (0)      (1)          (2)         
Server: Omega-X transfer_data: 0
Server: Omega-X factor_a: 0
Server: Omega-X slow: 0
Server: Omega-X factor_b: 0
Server: Omega-X score_retry: 0
Server: Omega-X damage_factor_c: 0
Server: Omega-X voice_ud: 0
Server: Omega-X alarm_factors_bl: 0
Server: Omega-X telemetry_x: 0
Server: Omega-X endstream: 0
Server: Omega-X celery: 0
Server: Omega-X awl: 0
Server: Omega-X trx: 0
Server: Omega-X points: 0
Server: Omega-X feature_factors_xf: 0
Server: Omega-X feature_factors_dc: 0

通过这种方式,我可以在同一个输出中处理任意数量的服务器,并且使用非常简单的正则表达式...

"Server:\s([a-zA-Z_.-]+)\s'([a-zA-Z_]+)':\s'(\d+)'"

所以我认为最好的方法是添加一个 Pre-Parser 来准备这样的数据,然后处理它......

事实上,你们俩都帮我解决了这个问题,非常感谢。

我想我会关闭这个问题,除非其他人有更好的主意:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 2017-12-30
    • 2021-07-09
    • 1970-01-01
    • 2017-09-13
    • 2011-03-11
    • 2017-01-07
    相关资源
    最近更新 更多