0

我正在尝试编写一些功能类似于谷歌日历快速添加功能的代码。您知道可以输入以下任何内容的那个:1) 2010 年 9 月 24 日,约翰生日 2) 约翰生日,2010 年 9 月 24 日 3) 2010 年 9 月 24 日,约翰·多伊生日 4) 2010 年 9 月 24 日:约翰5) 约翰生日 2010 年 9 月 24 日

它可以计算出我们想要一个日期为 24/9/2010 的事件将其余材料作为事件文本。

我想做的是 python 。

我正在考虑一种设计,我编写可能匹配上面列出的所有情况并提取日期的正则表达式。但我相信有一种更聪明的方法可以解决这个问题。因为我显然没有接受过词法分析或多种类型的解析器风格的培训。我正在寻找解决这个问题的好方法。

4

1 回答 1

2

注意:这里的python代码不正确!这只是它看起来的粗略伪代码。

正则表达式擅长从文本中以固定格式(例如 DD/MM/YYYY 日期)查找和提取数据。

词法分析器/解析器对擅长以结构化但有些可变的格式处理数据。词法分析器将文本拆分为标记。这些标记是给定类型(数字、字符串等)的信息单元。解析器采用这一系列标记并根据标记的顺序执行某些操作。

查看数据,您有一个基本的(主语、动词、宾语)结构,关系(人、“生日”、日期)的不同组合:

我将使用正则表达式将 29/9/10 和 24-9-2010 作为单个令牌处理,并将其作为日期类型返回。您可能可以对其他日期执行相同的操作,使用地图将 9 月和 9 月转换为 9。

然后,您可以将其他所有内容作为字符串返回(由空格分隔)。

然后你有:

  1. 日期','字符串'生日'
  2. 字符串 '生日' ',' 日期
  3. date 'birthday' 'of' 字符串 string
  4. 日期':'字符串字符串'生日'
  5. 字符串字符串“生日”日期

注意:'birthday'、','、':' 和 'of' 这里是关键字,所以:

class Lexer:
    DATE = 1
    STRING = 2
    COMMA = 3
    COLON = 4
    BIRTHDAY = 5
    OF = 6

    keywords = { 'birthday': BIRTHDAY, 'of': OF, ',': COMMA, ':', COLON }

    def next_token():
        if have_saved_token:
            have_saved_token = False
            return saved_type, saved_value
        if date_re.match(): return DATE, date
        str = read_word()
        if str in keywords.keys(): return keywords[str], str
        return STRING, str

    def keep(type, value):
        have_saved_token = True
        saved_type = type
        saved_value = value

除了 3 之外,所有的都使用人称的所有格形式('s如果最后一个字符是辅音,s如果它是元音)。这可能很棘手,因为 'Alexis' 可能是 'Alexi' 的复数形式,但由于您限制了复数形式的位置,因此很容易检测到:

def parseNameInPluralForm():
    name = parseName()
    if name.ends_with("'s"): name.remove_from_end("'s")
    elif name.ends_with("s"): name.remove_from_end("s")
    return name

现在,名称可以是first-namefirst-name last-name(是的,我知道日本交换了这些,但从处理的角度来看,上述问题不需要区分名字和姓氏)。下面将处理这两种形式:

def parseName():
    type, firstName = Lexer.next_token()
    if type != Lexer.STRING: raise ParseError()
    type, lastName = Lexer.next_token()
    if type == Lexer.STRING: # first-name last-name
        return firstName + ' ' + lastName
    else:
        Lexer.keep(type, lastName)
        return firstName

最后,您可以使用以下方式处理表格 1-5:

def parseBirthday():
    type, data = Lexer.next_token()
    if type == Lexer.DATE: # 1, 3 & 4
        date = data
        type, data = Lexer.next_token()
        if type == Lexer.COLON or type == Lexer.COMMA: # 1 & 4
            person = parsePersonInPluralForm()
            type, data = Lexer.next_token()
            if type != Lexer.BIRTHDAY: raise ParseError()
        elif type == Lexer.BIRTHDAY: # 3
            type, data = Lexer.next_token()
            if type != Lexer.OF: raise ParseError()
            person = parsePerson()
    elif type == Lexer.STRING: # 2 & 5
        Lexer.keep(type, data)
        person = parsePersonInPluralForm()
        type, data = Lexer.next_token()
        if type != Lexer.BIRTHDAY: raise ParseError()
        type, data = Lexer.next_token()
        if type == Lexer.COMMA: # 2
            type, data = Lexer.next_token()
        if type != Lexer.DATE: raise ParseError()
        date = data
    else:
        raise ParseError()
    return person, date
于 2010-06-30T23:59:49.917 回答