python使用变量和数字重新编译字符串

python使用变量和数字重新编译字符串,python,regex,nlp,Python,Regex,Nlp,您好,我想获得以下内容的匹配: test=re.compiler'[0-12]上午|下午[1-1000]天从昨天|今天|明天' 在这场比赛中: 打印测试。从今天起两天下午3点匹配 它不返回任何值,我做错了什么?我刚刚进入regex并阅读文档,我认为这应该有效!谢谢你的帮助 圣诞 ------------------------------------------- 我在问一个新问题,关于使用类似于NLP中上述流程的系统设计,请尝试以下方法: import re test = re.compil

您好,我想获得以下内容的匹配:

test=re.compiler'[0-12]上午|下午[1-1000]天从昨天|今天|明天'

在这场比赛中:

打印测试。从今天起两天下午3点匹配

它不返回任何值,我做错了什么?我刚刚进入regex并阅读文档,我认为这应该有效!谢谢你的帮助 圣诞

------------------------------------------- 我在问一个新问题,关于使用类似于NLP中上述流程的系统设计,请尝试以下方法:

import re

test = re.compile('^\s[0-1]?[0-9]{1}pm \d+ days from (today|yesterday|tomorrow)$')

print test.match(" 12pm 2 days from today")
test = re.compile(' \d+(am|pm) \d+ days from (yesterday|today|tomorrow)')
您遇到的问题是,无法在regex afaik中指定多个数字范围,因此必须将它们视为单个字符

试试这个:

import re

test = re.compile('^\s[0-1]?[0-9]{1}pm \d+ days from (today|yesterday|tomorrow)$')

print test.match(" 12pm 2 days from today")
test = re.compile(' \d+(am|pm) \d+ days from (yesterday|today|tomorrow)')

匹配后检查整数范围更容易,可读性更强:

m = re.match(r' (\d+)(?:pm|am) (\d+) days from (yesterday|today|tomorrow)',
             " 3pm 2 days from today")
assert m and int(m.group(1)) <= 12 and 1 <= int(m.group(2)) <= 1000
输出
如果要单独提取匹配的部分,可以使用?p[match]标记组。例如:

import re

pattern = re.compile(
    r'\s*(?P<time>1?[0-9])(?P<ampm>am|pm)\s+'
    r'(?P<days>[1-9]\d*)\s+days\s+from\s+'
    r'(?P<when>yesterday|today|tomorrow)\s*')

for time in range(0, 13):
    for ampm in ('am', 'pm'):
        for days in range(1, 1000):
            for when in ('yesterday', 'today', 'tomorrow'):
                text = ' %d%s %d days from %s ' % (time, ampm, days, when)
                match = pattern.match(text)
                assert match is not None
                keys = sorted(match.groupdict().keys())
                assert keys == ['ampm', 'days', 'time', 'when']

text = ' 3pm 2 days from today '
print pattern.match(text).groupdict()
编辑 在阅读了Rumple Stillskin和Demian Brecht之间的讨论后,我注意到我的上述主张很糟糕,因为它检测到字符串的某个结构,但它不能准确地验证它是一个好的时间模式字符串,因为它可以检测到从今天起2天的18pm

因此,我现在提出了一种模式,它允许精确地检测验证您需求的字符串,并指出每个字符串都具有与有效字符串相同的结构,但不具有有效良好时间模式字符串的所需值:

import re

regx = re.compile("(?<= )"  # better than a blank as first character
                  ""
                  "(?:(1[012]|\d)([ap]m) (?!0 )(\d{1,3}|1000)"
                  "|"
                  "(\d+)([ap]m) (\d+))"
                  ""
                  " days? from (yesterday|today|tomorrow)") # shared part




for ch in (" 12pm 2 days from today",
           " 4pm 1 day from today",
           " 12pm 0 days from today",
           " 12pm 1001 days from today",
           " 18pm 2 days from today",
           " 1212pm 2 days from today",
           " 12pm five days from today"):

    print ch
    mat = regx.search(ch)
    if mat:
        if mat.group(1):
            print mat.group(1,2,3,7),'\n# time-pattern-VALIDATED string #'
        else:
            print mat.group(4,5,6,7),'\n* SIMILI-time-pattern STRUCTURED string*'
    else:
        print '- NO STRUCTURED STRING in the text -'
    print
如果您只需要检测时间模式验证字符串的正则表达式,则只需

regx = re.compile("(?<= )(1[012]|\d)([ap]m) (?!0 )(\d{1,3}|1000) days?"
                  " from (yesterday|today|tomorrow)")
那怎么办

test = re.compile(r' ([0-9]|1[012])(am|pm) \d+ days from (yesterday|today|tomorrow)')
小时数部分应匹配0、1、…、9或10、11、12 但不是13,14,…,19


你可以用类似的方式限制1,…,1000的部分天数,即1000 |\d{1,3}。

这是我戴在戒指上的帽子。仔细研究这个正则表达式可以学到一些经验:

进口稀土 reobj=re.compile r松散地匹配日期/时间引用 ^锚定到字符串的开头。 \s*可选的前导空格。 ?P$时间:军事或上午/下午时间。 ?:军事时间选项组。 [2] [0-3]小时是20,21,22,23, |[01]?[0-9]或0-9、00-09或10-19 军事时间选项的结束组。 ?:分组进行可选分钟。 :小时和分钟间隔为: [0-5][0-9]00-59分钟 ? 军事会议记录是可选的。 |或时间以AM/PM格式给出。 ?:1[0-2]| 0?[1-9]1-12或01-12上午/下午选项小时 ?::[0-5][0-9]? 上午/下午时间的可选分钟数。 \s*上午/下午之前的可选空白。 [ap]m必需的AM或PM不区分大小写 时间选项的结束组。 \s+需要空格。 ?P\d+$offset:时间增量计数。 \s+需要空格。 ?P$单位:时间增量单位。 ?秒:一分钟小时星期月年十世纪 s时间单位可以有可选的复数s。 End$units:时间增量的单位。 \s+需要空格。 ?Pfrom | before | after | since dir:时间偏移方向。 \s+需要空格。 昨天|今天|明天|:对吗?现在 \结尾前的s*可选空格。 $Anchor到字符串的末尾。, re.IGNORECASE | re.VERBOSE match=reobj.匹配“从今天起2天的下午3点” 如果匹配: 打印时间:%s'%match.group'Time' 打印“偏移量:%s”%match.group“偏移量” 打印“单位:%s”%match.group“单位” 打印方向:%s'%match.group'dir' 打印“基本时间:%s”%match.group“基本” 其他: 打印不匹配。 输出:

{'time': '3', 'when': 'today', 'days': '2', 'ampm': 'pm'}
此正则表达式说明了需要吸取的一些经验教训:

正则表达式是非常强大和有用的! 这个正则表达式确实验证了这些数字,但正如您所看到的,这样做既麻烦又困难,因此不推荐使用它——我在这里展示它是为了演示为什么不这样做。简单地用正则表达式捕获数字,然后使用过程代码验证范围要容易得多。 命名捕获组减轻了从较大文本中提取多个数据子字符串的痛苦。 始终使用自由间距、冗余模式编写正则表达式,并适当缩进组和大量描述性注释。这有助于编写正则表达式以及以后的维护。 现代正则表达式构成了一种丰富而强大的语言。一旦您养成了编写冗长、适当缩进、注释良好的代码的习惯,那么即使是像上面这样的复杂正则表达式也很容易编写、阅读和维护。不幸的是,他们已经获得了困难、笨拙和容易出错的名声,因此没有重新开始 对于复杂的任务是值得称赞的



祝你快乐

第一个数字范围并没有正确地表达出来。在爱尔兰,这是一个深夜,我正在努力:等等,我在我的例子中复制了错误的代码,现在编辑你不能这样指定数字范围。[0-12]匹配0、1或2。不是介于0和12之间的数字。0-1是一个包含0和1的字符范围,2只是一个2…它匹配[]内的任何字符。而不是:[0-12]表示:匹配“0”到“1”范围内的一个字符,或2,[1-1000]表示:匹配“1”到“1”范围内的一个字符,或匹配“0”或“0”或“0”范围内的一个字符,[…]表达式是一个字符类,改为使用\d+,表示:匹配一个或多个数字。正则表达式很有趣!但我强烈建议花一两个小时学习基础知识。有一个很好的在线教程在:。你在那里度过的时间将为自己付出很多倍的代价。祝你快乐!我确实睡着了,因为是格林威治标准时间凌晨2点,哇!感谢大家的慷慨捐助,我将尝试各种方案。我的设计似乎有点超出了指定的要求。唯一的区别是我使用的是命名组。我建议这样做是因为这没有太多的工作,他将来可能会将其用于更复杂的模式,例如,给出了nlp标记,我个人也使用了相同的模式来更轻松地管理高度复杂的基于regexp的tokenizer.re.VERBOSE和每行一个捕获组可能更具可读性。正则表达式太过宽松,例如“从今天起0天内11119am”。真的认为它更具可读性吗?破译正则表达式和断言似乎需要更多的思考,而不仅仅是表达式。。尽管我的论点完全是主观的:@Demian Brecht:写一个无效的正则表达式,要么太严格,要么太宽松,比如你的答案中的正则表达式,可读性更高。f:当然,写不正确的正则表达式很容易,但如果你有具体的要求,然后,您应该能够制定一个匹配它们的表达式,而不必引入进一步的逻辑来确保表达式的有效性。再一次,只是我的拙见:@Damian:是的。IMHO,regex不应用于验证,而应仅用于确保文本结构正确。OTOH,这里几乎所有的答案都适用于无效的时间范围,例如从今天起2天19点,只是不确定你是否意识到。有趣的是,你可以在这里找到不同的观点,比如正则表达式应该和不应该用于什么:非常感谢,我把它改为:test=re.compiler“[1-9]| 1[012]am | pm\d+从昨天开始的几天|今天|明天”,以便只匹配从凌晨1-12点开始的时间0pm@ridgerunner哇!这样的作品和良好的反思+1.你似乎喜欢正则表达式。我99%同意你的想法。1%的不同之处在于,我更喜欢在括号之间的几行上写几个字符串->它们将被自动连接起来+甚至可以在每行末尾前放一条注释->修改相同的内容,我编辑了我的答案以显示这一点!有两个原因:我有点困惑,一个冗长的RE元素的边界在光学上是正确的吗??每一行都很模糊。以我的写作方式,我有不同颜色的评论和元素而且,由于在冗长的RE中没有考虑空格,有一次它给我带来了一个问题顺便说一下,我不觉得验证数字的表达式很麻烦。@eyquem:谢谢,是的,我非常喜欢正则表达式。我不理解你关于元素边界的问题-你能更详细地解释你的问题吗?@ridgerunner为我提供了一个RE字符串,它被提交到一个编译以给出一个已编译的正则表达式对象是由元素REs组成的?>=是元素RE,:2[0-3]|[01]?[0-9]是由元素REs组成的元素RE[2][0-3][01]?[0-9],由亚元素REs 2、[0-3]、[01]、[0-9]组成。。。。在你的RE中,我的大脑犹豫不定,不知道元素RE[2][0-3]:前面的空格是否在元素RE中,[2][0-3]之后在哪里停止,之间的空白[2 ] [0-3]和字符麻烦我,等等。@ RigGelunne每次我看到一个冗长的RE,我必须努力回忆一个事实,即在模式内的空白空白被忽略,除了当…等等»我没有立即察觉到边界限制,我应该在属于elemetal RE的字符和其外部空白之间书写。这就是为什么我更喜欢写一个全局RE,将元素RE堆叠成几行,每一行都用限制性引号分隔开来。这是主观的。你们寻找模式的方式很有趣,我喜欢这种方法,请参考我上面的评论和问题的第2部分,了解我的推理
regx = re.compile("(?<= )(1[012]|\d)([ap]m) (?!0 )(\d{1,3}|1000) days?"
                  " from (yesterday|today|tomorrow)")
test = re.compile(r' ([0-9]|1[012])(am|pm) \d+ days from (yesterday|today|tomorrow)')
r"""
Time:       3 pm
Offset:     2
Units:      days
Direction:  from
Base time:  today
"""