18

いくつかの日付値を含む文字列があり、それらをすべて解析したいと思います。文字列は自然言語なので、これまでに見つけた中で最も優れているのはdateutilです。

残念ながら、文字列に複数の日付値が含まれている場合、dateutilはエラーをスローします。

>>> s = "I like peas on 2011-04-23, and I also like them on easter and my birthday, the 29th of July, 1928"
>>> parse(s, fuzzy=True)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/pymodules/python2.7/dateutil/parser.py", line 697, in parse
    return DEFAULTPARSER.parse(timestr, **kwargs)
  File "/usr/lib/pymodules/python2.7/dateutil/parser.py", line 303, in parse
    raise ValueError, "unknown string format"
ValueError: unknown string format

長い文字列からすべての日付を解析する方法について何か考えはありますか?理想的にはリストを作成しますが、必要に応じて自分で処理することもできます。

私はPythonを使用していますが、現時点では、他の言語でも問題はありません。

PS-入力ファイルを途中で再帰的に分割して、うまくいくまで再試行できると思いますが、それはハックの地獄です。

4

4 に答える 4

18

それを見ると、最もハッキリしない方法は、dateutilパーサーを変更してファジー倍数オプションを持たせることです。

parser._parse文字列を受け取り、それをトークン化し_timelex、トークンを で定義されたデータと比較しparserinfoます。

ここで、トークンが のいずれにも一致しない場合、が True でparserinfoない限り、解析は失敗します。fuzzy

処理された時間トークンがない間は不一致を許可することをお勧めします。不一致が発生した場合は、その時点で解析されたデータを処理し、時間トークンの検索を再度開始します。

力を入れすぎてはいけません。


アップデート

パッチが適用されるのを待っている間...

これは少しハックで、ライブラリで非パブリック関数を使用しますが、ライブラリを変更する必要はなく、試行錯誤ではありません。float に変換できる単独のトークンがある場合、誤検知が発生する可能性があります。結果をさらにフィルタリングする必要がある場合があります。

from dateutil.parser import _timelex, parser

a = "I like peas on 2011-04-23, and I also like them on easter and my birthday, the 29th of July, 1928"

p = parser()
info = p.info

def timetoken(token):
  try:
    float(token)
    return True
  except ValueError:
    pass
  return any(f(token) for f in (info.jump,info.weekday,info.month,info.hms,info.ampm,info.pertain,info.utczone,info.tzoffset))

def timesplit(input_string):
  batch = []
  for token in _timelex(input_string):
    if timetoken(token):
      if info.jump(token):
        continue
      batch.append(token)
    else:
      if batch:
        yield " ".join(batch)
        batch = []
  if batch:
    yield " ".join(batch)

for item in timesplit(a):
  print "Found:", item
  print "Parsed:", p.parse(item)

収量:

発見: 2011 04 23
解析済み: 2011-04-23 00:00:00
発見: 1928 年 7 月 29 日
解析済み: 1928-07-29 00:00:00

ディーターのアップデート

Dateutil 2.1 は python3 との互換性のために書かれているようで、「互換性」ライブラリを使用していますsixstr何かが正しくなく、オブジェクトをテキストとして扱っていません。

文字列を Unicode またはファイルのようなオブジェクトとして渡す場合、このソリューションは dateutil 2.1 で機能します。

from cStringIO import StringIO
for item in timesplit(StringIO(a)):
  print "Found:", item
  print "Parsed:", p.parse(StringIO(item))

parserinfo にオプションを設定する場合は、parserinfo をインスタンス化し、それを parser オブジェクトに渡します。例えば:

from dateutil.parser import _timelex, parser, parserinfo
info = parserinfo(dayfirst=True)
p = parser(info)
于 2011-08-11T16:32:10.157 に答える
6

オフラインの間、昨日ここに投稿した回答に悩まされていました。はい、それは仕事をしましたが、不必要に複雑で非常に非効率的でした.

これは、はるかに優れた仕事をするはずの封筒の裏の版です!

import itertools
from dateutil import parser

jumpwords = set(parser.parserinfo.JUMP)
keywords = set(kw.lower() for kw in itertools.chain(
    parser.parserinfo.UTCZONE,
    parser.parserinfo.PERTAIN,
    (x for s in parser.parserinfo.WEEKDAYS for x in s),
    (x for s in parser.parserinfo.MONTHS for x in s),
    (x for s in parser.parserinfo.HMS for x in s),
    (x for s in parser.parserinfo.AMPM for x in s),
))

def parse_multiple(s):
    def is_valid_kw(s):
        try:  # is it a number?
            float(s)
            return True
        except ValueError:
            return s.lower() in keywords

    def _split(s):
        kw_found = False
        tokens = parser._timelex.split(s)
        for i in xrange(len(tokens)):
            if tokens[i] in jumpwords:
                continue 
            if not kw_found and is_valid_kw(tokens[i]):
                kw_found = True
                start = i
            elif kw_found and not is_valid_kw(tokens[i]):
                kw_found = False
                yield "".join(tokens[start:i])
        # handle date at end of input str
        if kw_found:
            yield "".join(tokens[start:])

    return [parser.parse(x) for x in _split(s)]

使用例:

>>> parse_multiple("I like peas on 2011-04-23, and I also like them on easter and my birthday, the 29th of July, 1928")
[datetime.datetime(2011, 4, 23, 0, 0), datetime.datetime(1928, 7, 29, 0, 0)]

dateutil.parser.parse空/不明な文字列を処理する場合とは動作がわずかに異なることに注意してください。Dateutil は現在の日をparse_multiple返しますが、空のリストを返しますが、これは予想通りです。

>>> from dateutil import parser
>>> parser.parse("")
datetime.datetime(2011, 8, 12, 0, 0)
>>> parse_multiple("")
[]

PS非常によく似たことを行うMattHの更新された回答を見つけました。

于 2011-08-11T16:34:57.837 に答える
0

「単語」を配列に入れれば、うまくいくはずです。これにより、日付かどうかを確認し、変数に入れることができます。

日付を取得したら、datetime ライブラリライブラリを使用する必要があります。

于 2011-08-11T16:58:15.267 に答える
0

日付が表示される可能性のあるすべての形式をカバーする正規表現パターンを作成してから、正規表現を起動してテキストを調べてみませんか? 日付を文字列で表現する作法は何十通りも無いと思います。

唯一の問題は、日付の式の最大数を収集することです

于 2011-08-11T19:13:36.107 に答える