2

こんにちは、私は非常によく形成された文字列をそのコンポーネントの断片に解析しようとしています。文字列は非常に JSON に似ていますが、厳密に言えば JSON ではありません。それらは次のように形成されます。

createdAt=Fri Aug 24 09:48:51 EDT 2012, id=238996293417062401, text='Test Test', source="Region", entities=[foo, bar], user={name=test, locations=[loc1,loc2], locations={comp1, comp2}}

テキストのチャンクとしての出力では、この時点で特別なことをする必要はありません。

createdAt=Fri Aug 24 09:48:51 EDT 2012 
id=238996293417062401 
text='Test Test' 
source="Region"
entities=[foo, bar] 
user={name=test, locations=[loc1,loc2], locations={comp1, comp2}}

次の式を使用して、ほとんどのフィールドを分離することができます

,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))(?=(?:[^']*'[^']*')*(?![^']*'))

これは、どのタイプの引用符でもないすべてのコンマで分割されますが、角括弧や中括弧でもないコンマで分割される場所に飛躍することはできないようです。

4

2 に答える 2

2

ネストされた括弧/ブラケットを処理したいので、それらを処理する「正しい」方法は、それらを個別にトークン化し、ネストレベルを追跡することです。したがって、単一の正規表現ではなく、さまざまなトークン タイプに対して複数の正規表現が必要です。

これは Python ですが、Java への変換はそれほど難しくありません。

# just comma
sep_re = re.compile(r',')

# open paren or open bracket
inc_re = re.compile(r'[[(]')

# close paren or close bracket
dec_re = re.compile(r'[)\]]')

# string literal
# (I was lazy with the escaping. Add other escape sequences, or find an
# "official" regex to use.)
chunk_re = re.compile(r'''"(?:[^"\\]|\\")*"|'(?:[^'\\]|\\')*[']''')

# This class could've been just a generator function, but I couldn;'t
# find a way to manage the state in the match function that wasn't
# awkward.
class tokenizer:
  def __init__(self):
    self.pos = 0

  def _match(self, regex, s):
    m = regex.match(s, self.pos)
    if m:
      self.pos += len(m.group(0))
      self.token = m.group(0)
    else:
      self.token = ''
    return self.token

  def tokenize(self, s):
    field = '' # the field we're working on
    depth = 0  # how many parens/brackets deep we are
    while self.pos < len(s):
      if not depth and self._match(sep_re, s):
        # In Java, change the "yields" to append to a List, and you'll
        # have something roughly equivalent (but non-lazy).
        yield field
        field = ''
      else:
        if self._match(inc_re, s):
          depth += 1
        elif self._match(dec_re, s):
          depth -= 1
        elif self._match(chunk_re, s):
          pass
        else:
          # everything else we just consume one character at a time
          self.token = s[self.pos]
          self.pos += 1
        field += self.token
    yield field

使用法:

>>> list(tokenizer().tokenize('foo=(3,(5+7),8),bar="hello,world",baz'))
['foo=(3,(5+7),8)', 'bar="hello,world"', 'baz']

この実装には、いくつかのショートカットが必要です。

  • 文字列エスケープは非常に怠惰です:\"二重引用符で囲まれた文字列と\'単一引用符で囲まれた文字列のみをサポートします。これは簡単に修正できます。
  • ネストレベルのみを追跡します。括弧が (括弧ではなく) 括弧と一致していることは確認しません。それが気になる場合はdepth、ある種のスタックに変更して、それに括弧/ブラケットをプッシュ/ポップすることができます。
于 2013-02-06T00:34:32.060 に答える
1

コンマで分割する代わりに、次の正規表現を使用して、必要なチャンクを一致させることができます。

(?:^| )(.+?)=(\{.+?\}|\[.+?\]|.+?)(?=,|$)

パイソン:

import re
text = "createdAt=Fri Aug 24 09:48:51 EDT 2012, id=238996293417062401, text='Test Test', source=\"Region\", entities=[foo, bar], user={name=test, locations=[loc1,loc2], locations={comp1, comp2}}"
re.findall(r'(?:^| )(.+?)=(\{.+?\}|\[.+?\]|.+?)(?=,|$)', text)

>> [
    ('createdAt', 'Fri Aug 24 09:48:51 EDT 2012'), 
    ('id', '238996293417062401'), 
    ('text', "'Test Test'"), 
    ('source', '"Region"'), 
    ('entities', '[foo, bar]'), 
    ('user', '{name=test, locations=[loc1,loc2], locations={comp1, comp2}}')
   ]

「キー」と「値」を分離するようにグループ化を設定しました。Javaでも同じことを行います-Javaでの動作をここで確認してください:

http://www.regexplanet.com/cookbook/ahJzfnJlZ2V4cGxhbmV0LWhyZHNyDgsSBlJlY2lwZRj0jzQM/index.html

正規表現の説明:

  • (?:^| )行頭またはスペースに一致する非キャプチャ グループ
  • (.+?)の前の「キー」に一致します...
  • =等号
  • (\{.+?\}|\[.+?\]|.+?)一連の{文字}[文字]、または文字のみのいずれかに一致します
  • (?=,|$),aまたは行末に一致する先読み。
于 2013-02-05T21:36:50.663 に答える