0

Googleカレンダーのクイック追加機能のように機能するコードを書き込もうとしています。1) 2010 年 9 月 24 日、John の誕生日 2) John の誕生日、2010 年 9 月 24 日 3) 2010 年 9 月 24 日、John Doe の誕生日 4) 24-9-2010 : John誕生日 5) ジョンは 2010 年 9 月 24 日に誕生日を迎えます

そして、2010 年 9 月 24 日のイベントの残りの部分をイベント テキストとして使用する必要があることがわかります。

これをやりたいのは python です。

上記のすべてのケースに一致する可能性のある正規表現を記述し、日付を抽出するデザインを考えています。しかし、この問題に取り組むためのよりスマートな方法があると確信しています。私は明らかに字句解析や多くの種類のパーサー スタイルの訓練を受けていないためです。この問題にアプローチする良い方法を探しています。

4

1 に答える 1

2

注: ここの python コードは正しくありません! これは、どのように見えるかの大まかな擬似コードです。

正規表現は、固定形式 (例: DD/MM/YYYY 日付) のテキストからデータを見つけて抽出するのに適しています。

レクサー/パーサーのペアは、構造化されたデータを処理するのに適していますが、多少可変の形式です。レクサーはテキストをトークンに分割します。これらのトークンは、特定のタイプ (数値、文字列など) の情報の単位です。パーサーはこの一連のトークンを受け取り、トークンの順序に応じて何かを行います。

データを見ると、関係 (人、「誕生日」、日付) のさまざまな組み合わせで基本的な (主語、動詞、目的語) 構造があります。

正規表現を使用して 29/9/10 と 24-9-2010 を単一のトークンとして処理し、日付型として返します。9 月と 9 月を 9 に変換するマップを使用して、おそらく他の日付についても同じことができます。

次に、他のすべてを文字列として返すことができます (空白で区切られます)。

次に、次のものがあります。

  1. 日付 ',' 文字列 '誕生日'
  2. 文字列「誕生日」「,」日付
  3. 日付「誕生日」「の」文字列文字列
  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

さて、name は or のいずれかですfirst-name(first-name last-nameはい、日本ではこれらが入れ替わっていることは知っていますが、処理の観点からは、上記の問題で名字と姓を区別する必要はありません)。以下は、これら 2 つの形式を処理します。

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 に答える