给定一个字符串,生成一个可以解析*类似*字符串的正则表达式

例如,给定字符串“2009/11/12”我想得到正则表达式(“\ d {2} / d {2} / d {4}”),所以我将能够匹配“2001 / 01/02“也是。

有什么东西可以做到吗? 相似的东西? 任何想法’如何做到这一点?

有text2re ,一个免费的基于Web的“正则表达式”生成器。

但我不认为这在源代码中可用。 我敢说没有自动正则表达式生成器可以在没有用户干预的情况下正确使用它,因为这需要机器知道你想要什么。


请注意,text2re使用基于模板,模块化和非常通用的方法来生成正则表达式。 它生成的表达式有效,但它们比同等的手工制作表达式复杂得多。 它不是学习正则表达式的好工具,因为它在设置示例时做得非常糟糕。

例如,字符串"2009/11/12"将被识别为yyyymmdd模式,这是有帮助的。 该工具将其转换为这个 125个角色的怪物:

 ((?:(?:[1]{1}\d{1}\d{1}\d{1})|(?:[2]{1}\d{3}))[-:\/.](?:[0]?[1-9]|[1][012])[-:\/.](?:(?:[0-2]?\d{1})|(?:[3][01]{1})))(?![\d]) 

手工制作的等价物仅占五分之二(50个字符):

 ([12]\d{3})[-:/.](0?\d|1[0-2])[-:/.]([0-2]?\d|3[01])\b 

为您的问题编写一般解决方案是不可能的。 问题是任何发电机可能都不知道你要检查什么,例如是否应该允许“2312/45/67”? “2009.11.12”怎么样?

你能做的就是自己编写一个适合你确切问题的发生器,但是一般的解决方案是不可能的。

对不起,但你所谓的不可能显然是一项可以实现的任务。 它不能给出所有例子的结果,也许不是最好的结果,但你可以给它各种提示,它会让生活变得简单。 下面将举几个例子。

另外,翻译结果的可读输出将非常有用。 就像是:

  • “搜索:以非数字字母开头并以字符串结尾的单词:”ing“。
  • 或者: 搜索:其中包含bbb的文本,然后是zzz
  • 或:*搜索:看起来如此“aa / bbbb / cccc”的模式,其中“/”是分隔符,“aa”是两位数,“bbbb”是任意长度的单词,“cccc”是四位数之间的数字1900年和2020年*

也许我们可以使用SQL类型的语言创建一个“后台翻译器”来创建正则表达式,而不是以怪诞的方式创建它。

以下是一些可行的示例:

 class Hint: Properties: HintType, HintString enum HintType { Separator, ParamDescription, NumberOfParameters } enum SampleType { FreeText, DateOrTime, Formatted, ... } public string RegexBySamples( List samples, List sampleTypes, List hints, out string GeneralRegExp, out string description, out string generalDescription)... regex = RegExpBySamples( {"11/November/1999", "2/January/2003"}, SampleType.DateOrTime, new HintList( HintType.NumberOfParameters, 3 )); regex = RegExpBySamples( "123-aaaaJ-1444", SampleType.Format, HintType.Seperator, "-" ); 

用于标记示例文本或输入文本的GUI,也可以添加到正则表达式。 首先,您标记日期(“样本”),并选择是否已格式化此文本,或者您是否正在构建格式,以及格式类型是什么:自由文本,格式化文本,日期,GUID或选择…从现有格式(您可以存储在库中)。

让我们为此设计一个规范,并使其成为开源…任何人都想加入?

我尝试过一种非常天真的方法:

 class RegexpGenerator { public static Pattern generateRegexp(String prototype) { return Pattern.compile(generateRegexpFrom(prototype)); } private static String generateRegexpFrom(String prototype) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < prototype.length(); i++) { char c = prototype.charAt(i); if (Character.isDigit(c)) { stringBuilder.append("\\d"); } else if (Character.isLetter(c)) { stringBuilder.append("\\w"); } else { // falltrought: literal stringBuilder.append(c); } } return stringBuilder.toString(); } private static void test(String prototype) { Pattern pattern = generateRegexp(prototype); System.out.println(String.format("%s -> %s", prototype, pattern)); if (!pattern.matcher(prototype).matches()) { throw new AssertionError(); } } public static void main(String[] args) { String[] prototypes = { "2009/11/12", "I'm a test", "me too!!!", "124.323.232.112", "ISBN 332212" }; for (String prototype : prototypes) { test(prototype); } } } 

输出:

2009/11/12 – > \ d \ d \ d \ d / \ d \ d / \ d \ d
我是一个测试 – > \ w’\ w \ w \ w \ w \ w \ w
我也是!!! – > \ w \ w \ w \ w \ w !!!
124.323.232.112 – > \ d \ d \ d。\ d \ d \ d。\ d \ d \ d。\ d \ d \ d
ISBN 332212 – > \ w \ w \ w \ w \ d \ d \ d \ d \ d \ d

如其他人已经概述的那样,这个问题的一般解决方案是不可能的 此类仅适用于少数情况

不,你不能得到一个与你想要的可靠匹配的正则表达式,因为正则表达式不包含有关输入的语义信息(即它需要知道它为日期生成一个正则表达式)。 如果问题仅与日期有关,我建议尝试使用多个正则表达式,看看其中一个是否匹配所有正则表达式。

我不确定这是否可行,至少没有很多样本字符串和一些学习算法。

有许多匹配的正则表达式,并且一个简单的算法不可能选择“正确”的算法。 你需要给它一些分隔符或其他东西来寻找,所以你不妨自己编写正则表达式。

听起来像机器学习问题。 您必须手头有多个示例(更多)并指示每个示例是否被视为匹配。

洛雷托差不多这样做了。 它是一个开源实现,使用常见的最长子串来生成正则表达式。 但是,当然需要多个例子。

我不记得这个名字,但如果我的计算单元理论服务于我,理论上它是不可能的:)

我没有找到任何可以做到这一点,但由于问题域相对较小(你会惊讶有多少人使用最奇怪的日期格式),我能够编写某种“日期正则表达式生成器” 。 一旦我对unit testing感到满意,我就会发布它 – 以防万一有人会需要这样的东西。

感谢所有回答的人(排除了(。*)的人 – 笑话很棒,但这个是sssssssssoooo跛脚:))

除了提供“良好”输入的学习算法示例之外,您还可以将其输入“坏”输入,以便知道不要查找的内容。 例如,电话号码中没有字母。