【问题标题】:Regex creation based upon input基于输入的正则表达式创建
【发布时间】:2012-05-22 13:31:50
【问题描述】:

我有一个 Web 应用程序,用 PHP 编写,包含 Javascript 和 JQuery,将用作我公司的库存管理系统 (IMS)。我希望能够创建一个基于用户输入值的正则表达式。

这背后的想法是,大多数制造商的序列号架构、字符长度以及字母与数值的混合对于某个部分来说是唯一的。因此,当将零件添加到 IMS 并将第一个序列号扫描到系统中时,我希望构建一个 Regex 语句并将其保存到与该零件类型对应的数据库表中。以后扫描序列号时,应自动选择部件作为部件类型,因为它与该制造商的序列号模式匹配。我知道这种方法可能并不总是适用于单个部件,因此我什至可以返回与架构匹配的部件列表,而不是用户需要在目录中查找它。

我的问题的基础是,让代码中的函数能够破译用户提供的值以创建正则表达式的最佳起点是什么?我不是要求一个完整的功能,而是一个如何看待我的情况和目标的起点,这样我就可以了解从哪里开始。我已经挠头够久了,开始编写函数无数次,只是为了删除整个块,因为我知道我正走向灾难。

代码中的任何事情都是可能的——这可行吗?


编辑 - 添加样本值

DVD-RW(光驱)

  • 1613518L121
  • 1613509L121
  • 1613519L121

VGA 输出卡

  • 0324311071068
  • 0324311071134

COM 扩展卡

  • 608131234
  • 608131237

硬盘

  • WMAYUJ753738
  • WMAYUJ072099
  • WMAYUJ683739
  • WMAYUJ844900

如您所见,某些值将只是特定长度字符的数字。其他人将在开头有字母字符,后跟一系列数字。其他人可能有相互穿插的字母/数字字符。在大多数情况下,一个简单的字母/数字规则长度将适合识别我们商品列表中的单个零件类型。但是,在多个表达式匹配一个值的情况下,我可以简单地让应用程序显示两个或多个与正则表达式匹配的产品的列表,并提示用户选择正确的部分。总体而言,这将节省在 WMS 数据库中选择产品类型的时间和错误。

感谢 cmets。我知道我问的问题不是只有一个答案。我正在寻找一个起点,了解如何最好地逐步遍历字符串并吐出与该值匹配的相应 Regex 语句。

【问题讨论】:

  • 我认为你做不到。你不能根据一个例子制定规则。无论如何,这是我的看法。
  • Pete,您认为创建一个有效的表达式需要多少样本?或者你是在暗示整个想法本身是无效的?
  • 啊。那完全是另一回事。这有点像破解密码,不是吗?在我看来,危险在于您根据 X 个案例制定规则,然后因为该规则在某些方面存在缺陷而退回大量数据。
  • 但是不要让我阻止你尝试 - 这可能是一个迷人的项目。你有例子吗?
  • 也许你可以分步处理?另外,如果你有一些样本值,我很确定你会有其他的回复?顺便说一句,我会尝试首先搜索在处理正则表达式时必须保护的特殊字符(如点 [.],在这些字符上拆分我的值)或可以被视为分隔符的字符,如“-”或“_”(想想 ISBN 号)。然后让一些类匹配,如 [0-9]+、[A-Z]+ 或 [a-z]+ 加上它们的长度(最小、最大)提取?这样您就可以拥有一些自定义规则,例如 'myLettersWithLengthX' + (mySeparators('-')) + myNumbersLengthBetween(m,n)...

标签: php javascript regex


【解决方案1】:

正如@Pete 所说,我认为您为自己设定的目标过于雄心勃勃。一些想法,可能根据您的具体需求过于概括。

我认为您想扫描 1-56592-487-8 之类的序列号并推断正则表达式 /\d-\d{5}-\d{3}-\d/ 匹配来自给定制造商的这种类型。 (这恰好是我的“Java in a Nutshell”副本的 ISBN-10。ISBN 不是序列号,而是与我一起使用。)但是您无法从少数示例中推断出制造商使用的模式。也许第一个字符位置是一个十六进制数字 (0-F)。也许最后一个字符是校验和,可以是数字或 X(如 ISBN)。也许有一个后缀,并不总是存在,表示植物。因此,随着新零件实例的出现,您会发现自己为相同的制造商/零件类型构建了许多模式。

你也会遇到相反的问题。小部件制造商使用正则表达式 /[A-Z]{3}\d{7}/,声波螺丝刀制造商使用相同的模式。

也就是说,你能做的最好的事情是这样的:

for each character in the scanned serial number
    if it is a capital letter
        add [A-Z] to the regular expression
    else if it is a digit
        add \d to the regular expression
    else 
        add the character itself to the regular expression, escaped as necessary
 end for
 collapse multiple occurrences with the {,} interval qualifier

Vehicle Identification Numbers 的规则也可能是鼓舞人心的。举几个例子,想想你将如何推断 VIN 的规则。

【讨论】:

  • 您的回复是有效的,我理解您的意思。 ISBN 虽然是一个很好的例子,但并不适合模型,因为无论出版商如何,ISBN 编号都是相同的格式。制造商为零件创建唯一序列号的模式不是公认的标准。不管序列号中的一个字符是否是校验和,它仍然是一个可以通过Regex进行验证的字符。您的代码示例很有意义,是一个很好的起点。也许这就像这个例程需要的一样复杂,或者也许有一些东西可以使它更健壮。
【解决方案2】:

编辑:抱歉,我的示例代码有问题,您需要这种算法作为您猜测的部分的第一步:longest substringthis

您将需要添加迭代和一些掩蔽,就像上面和 David 解释的那样,也在下面的示例中,DVD-RW 的“L121”没有被猜到(因为我已经说过我必须以“普通”开头)。因此,您需要找到所有常见的连续子序列并确定哪些是相关的! (可能带有一种最大化增益函数)

使用第二个链接 long_substr :

>>> for x in d:
    for y in d:
        if x == y: continue
        common = long_substr([x, y])
        length = len(common)
        if x.startswith(common) and y.startswith(common):
            print "\t".join((x, y, str(length), common))

产生 =>

0324311071068   0324311071134   10  0324311071
0324311071134   0324311071068   10  0324311071
1613519L121 1613518L121 6   161351
1613519L121 1613509L121 5   16135
WMAYUJ844900    WMAYUJ753738    6   WMAYUJ
WMAYUJ844900    WMAYUJ072099    6   WMAYUJ
WMAYUJ844900    WMAYUJ683739    6   WMAYUJ
WMAYUJ753738    WMAYUJ844900    6   WMAYUJ
WMAYUJ753738    WMAYUJ072099    6   WMAYUJ
WMAYUJ753738    WMAYUJ683739    6   WMAYUJ
1613518L121 1613519L121 6   161351
1613518L121 1613509L121 5   16135
WMAYUJ072099    WMAYUJ844900    6   WMAYUJ
WMAYUJ072099    WMAYUJ753738    6   WMAYUJ
WMAYUJ072099    WMAYUJ683739    6   WMAYUJ
WMAYUJ683739    WMAYUJ844900    6   WMAYUJ
WMAYUJ683739    WMAYUJ753738    6   WMAYUJ
WMAYUJ683739    WMAYUJ072099    6   WMAYUJ
608131237   608131234   8   60813123
1613509L121 1613519L121 5   16135
1613509L121 1613518L121 5   16135
608131234   608131237   8   60813123

--- 第一个错误回复从这里开始

下面是我回复的第一部分,它只能帮助你理解我错在哪里,可能会给你一些想法:

使用最长公共子序列问题求解器LCS 的示例满足您的特殊需求,我可以认为这是猜测什么是常见的过程的第一步?

它在 Python 中,但对于演示部分,假设您使用上面第一个链接的 ActiveState 代码食谱,它可以很容易阅读(或者可以在 IDLE(python 编辑器)中剪切和粘贴)

这与生物信息学有关(想想基因对齐)

您将需要一些东西来确定最有趣的常见序列是什么(可能有最小的长度?然后像大卫已经提出或在我的评论中提出的那样进行掩蔽

(起初我没有看到 LCS 不是 LCS 连续求解器,而您需要它!所以我第一次使用 LCS 求解器时有问题 :( 因为它不是连续的,我有 MAYUJ8 或WMAYUJ7 而不是 WMAYUJ - 更短!而求解器找到最长的常见字符而不期望它们是连续的! - 再次抱歉)

>>> raw = """1613518L121
1613509L121
1613519L121

0324311071068
0324311071134

608131234
608131237

WMAYUJ753738
WMAYUJ072099
WMAYUJ683739
WMAYUJ844900"""
>>> d = dict()
>>> for line in raw.split("\n"):
    if not line.strip(): continue
    value = line.strip()
    d[value] = 1

>>> for x in d:
    for y in d:
        if x == y: continue
        length = LCSLength(x, y)
        common = LCS(x,y)
        if  length >= 3 and x.startswith(common):
            print "\t".join((x, y, str(length), common))

产生 =>

0324311071068   0324311071134   10  0324311071
0324311071068   608131234   4   0324
0324311071134   0324311071068   10  0324311071
WMAYUJ844900    WMAYUJ753738    7   WMAYUJ8
WMAYUJ753738    WMAYUJ072099    7   WMAYUJ7
608131237   608131234   8   60813123
608131234   608131237   8   60813123

【讨论】:

    【解决方案3】:

    运行垃圾邮件检测算法(统计算法,如贝叶斯或类似的“学习”算法)。这会或不会帮助你,但如果没有,我真的怀疑你会在这里做出任何有用的逻辑算法。

    【讨论】:

      猜你喜欢
      • 2016-01-21
      • 1970-01-01
      • 2014-10-14
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 2011-07-20
      • 1970-01-01
      • 2010-12-04
      相关资源
      最近更新 更多