2016-06-17 5 views
1

私は(1よりよいがある場合、またはその他の方法)という文字列を分割するために、正規表現を見つけようとしていますスプリットSQLは、キーと値のペアに文を挿入文字列として次の文を考える

stmt = "insert into table (col1, col2, col3) values (100, '() string with parantheses()', 2.3);" 

私は、後に列名を持つdicionaryを記入し、これまでのところ、私は好きではない(というか、私が唯一の正規表現を使用したソリューションがあります信じて、次のソリューションを持っている

d = { "col1" : "100", "col2" : "'() string with parantheses()'", "col3" : "2.3" } 

値ができることを["(col1, col2, col3)", "(100, '() string with parantheses()', 2.3)"]ようなリストへ同じことをする)。

re.findall("\([^\r\n]*\)", stmt)[0].split("values") 
# from here on I would have to parse the two strings and fill a dict 

私は唯一の正規表現を使用して'values'で文字列を分割する必要はありません解決策を見つけることができないのです。私の主な問題は、値が入っている2番目のparantheses文字列が文字列にparantheses自身を含むかもしれないということです。

答えて

1

ステートメントが常に同じ形式である場合は、基本的な文字列操作とast.literal_evalを使用して値を評価することができます。これは、int型、str型、およびfloat型の値で終わることにも注意してください。

import ast 
import csv 

stmt = "insert into table (col1, col2, col3) values (100, '() string with parantheses()', 2.3);" 
pre, values = stmt.rstrip(';').partition(' values ')[::2] 
cols = pre.partition('(')[2] 
d = dict(zip(cols.rstrip(')').split(', '), ast.literal_eval(values))) 

これはあなたを与えるだろう:

{'col1': 100, 'col2': '() string with parantheses()', 'col3': 2.3} 
+0

これは有望ではありますが、行3( 'pre.partition( 'table')')でパーティション化するのはunfotunlyです。これは、実際のテーブル名であり、ステートメントのキーワードではないためです。申し訳ありませんが、テーブル名の例としては悪い選択でした。 – ap0

+0

@ ap0 d0h - はい...愚かな私...代わりにかっこを使用することができます - コード –

+0

@ ap0を更新しました。https:// sqlparseもご覧ください。readthedocs.io/en/latest/intro/ - 私はそれを使って素早く遊びました。仕事をより柔軟にするように見えますが、解析された構造をナビゲートする作業をする必要があります。テキストの書式を保証することができます。 –

0

まあ、これは美しいではありませんが、あなたがで作業文字列は常に(それらの特性に基づいて)insert文になると仮定すると、これは動作するはずです:

stmt = "insert into table (col1, col2, col3) values (100, '() string with parantheses()', 2.3);" 

# if it will always be an insert statement, the following will work. 
par1 = stmt[stmt.find("(") + 1:stmt.find(") values")] 
par2 = stmt[stmt.find("values (") + 8:-2] 

par1_list = par1.split(",") 
par2_list = par2.split(",") 

d = dict(zip(par1_list, par2_list)) 

print(d) # prints: {' col2': " '() string with parantheses()'", ' col3': ' 2.3', 'col1': '100'} 

あなたは他の挿入文を持っている場合は、試してみてくださいこれが動作するかどうかを教えてください。おかげさまで

+1

これは値の文字列もcomを含む場合、予期しない結果を与えることに注意してくださいマス... –

+0

@JonClements真実は、それを考えなかった。ありがとう。 –

2

これらの醜いハックとなぜ混乱? SQLにSQLを解析させます。ここではタプルに任意のinsert文を有効にする完全なプログラムです:もちろん

my_insert = """insert into some_table (col1, col2, col3) values (100, 
             '() string with parantheses()', 2.3);""" 

import sqlite3 
conn = sqlite3.connect(":memory:") 
conn.execute("create table some_table (col1, col2, col3)") 
conn.execute(my_insert) 
parsed_rows = list(conn.execute("select * from some_table")) 
conn.close() 

print(parsed_rows) 
# Output: 
[(100, '() string with parantheses()', 2.3)] 

あなたはまた、実際にデータベースにデータを保存するのではなく、あなたが今、彼らと行うことを計画しているものは何でも検討する必要があります。その場合、接続を確立するときに":memory:"の代わりにファイル名を使用すると、永続ストレージが取得されます。

+1

しかし、私は 'sqlite3.connect( ':memory:')'を使って、潜在的に奇妙なことが起こって再利用するのを防ぐために、少しのファイルがぶら下がってDBを閉じないようにしたいと思います。また、名前付きカーソルを使用して、OPが達成しようとしているものの一部である列名も含むようにすることができます。 –

+0

良い提案、ありがとう。 – alexis

+0

、ヘッダーの場合は "PRAGMA table_info(some_table)"、fetchall()のようなPRAGMAステートメントを使用し、返されたリストのリストからインデックス1の項目をリストすることができます。 –

0

あなたが本当にこれをしたい場合は、あなたの正規表現はアサーション式を併発していることになります:

は「値」

match = re.findall("""(?<!\') # No preceeding ' before (
        \(
        (?!\)) # A closing parenthesis must not follow a (
        [^\r\n]*? 
        (?<!\() # An opening parenthesis must not precede a) 
        \) 
        (?!\') # No following ' immedaitely after) 
        """, stmt, re.VERBOSE) 
# ['(col1, col2, col3)', "(100, '() string with parantheses()', 2.3)"] 

r = [o.strip() for i in match for o in i[1:-1].split(',')] 
d = dict(zip(*r)) 
# {'col1': '100', 'col3': '2.3', 'col2': "'() string with parantheses()'"} 

で文字列を分割する必要はありませんあなたは正しいのSQLソリューションと一緒に行く必要があります

関連する問題