質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Pythonista

Pythonistaは、iOS上でPythonプログラミングができる開発アプリです。さらに、Pythonの関数・変数などを自動で補完する便利なコードエディタや、PythonスクリプトをiOS上で多様な形で機能させる各種機能も内包しています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1446閲覧

Python 範囲指定及び値の取り出し

polpop

総合スコア6

Pythonista

Pythonistaは、iOS上でPythonプログラミングができる開発アプリです。さらに、Pythonの関数・変数などを自動で補完する便利なコードエディタや、PythonスクリプトをiOS上で多様な形で機能させる各種機能も内包しています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/07/18 17:11

編集2020/07/18 19:42

#実現したい事
sample.txtから条件に合う特定の値を出力したいです。
(結果1~10までの内容が記入されています。)
条件は
『SQL order by Elapsed time』の結果範囲で、"module:"を含む場合は、その範囲内で記載のあるsql文を一行で抽出したいと思っています。

#txtから抽出したい値
① select owner#,name,namespace,remoteowner,linkname,p_timestamp,p_obj#, nvlp_obj#=obj#(+) order by order# (1行で)

② select /*+ rule */ bucket_cnt, row_cnt, cache_cnt, null_cnt, timestamp#, sample_
size, minimum, maximum, distcnt, lowval, hival, density, col#, spare1, spare2, a
vgcln, minimum_enc, maximum_enc from hist_head$ where obj#=:1 and intcol#=:2(1行で)

#sample.txt中身 ※#結果1~4は実際のテキストには記載はありません。

SQL order by Elapsed time #結果1 ------------------------- 100 100 100 module: select owner#,name,namespace,remoteowner,linkname,p_timestamp,p_obj#, nvlp_obj#=obj#(+) order by order# SQL order by psychical time #結果2 ------------------------- 300 300 300 module: select p_obj#, nvlp_obj#=obj#(+) order by order# SQL order by Elapsed time #結果3 ------------------------- 200 200 200 module: select /*+ rule */ bucket_cnt, row_cnt, cache_cnt, null_cnt, timestamp#, sample_ size, minimum, maximum, distcnt, lowval, hival, density, col#, spare1, spare2, a vgcln, minimum_enc, maximum_enc from hist_head$ where obj#=:1 and intcol#=:2 SQL order by Elapsed time #結果4 ------------------------- Elapsed: 200 200 200 select ringo ringo ringo mikan mikan mikan mikan ~~結果5,6,7と続く(上記以外のパターンの情報もあり)

#試した事

色々考えて行いましたが全く上手くいきません。。
本当にお手上げ状態です。。。。
条件に当てはまる最初の1行しか抽出できません。。
ファイル内全体で条件に当てはまる物をすべて抽出したいのですが。。
(※他にもたくさん試しましたが以下のコードが一番実現したかった事に近かったです。
他に試した内容が必要な場合はコメントください。)

import re filepath = 'C:\Users\Desktop\新しいフォルダー\sample.txt' def extract_text_in_file(filepath, pattern_prev, pattern_next): extracted_text_array = [] with open(filepath, "r", encoding="utf-8") as f: is_extracting = False for line in f: line = line.rstrip() if not is_extracting: if re.match(pattern_prev, line): is_extracting = True continue if re.match(pattern_next, line): break extracted_text_array.append(line.rstrip()) return extracted_text_array pattern_prev = r'Module:' pattern_next = r'^$' extracted_text_array = extract_text_in_file(filepath, pattern_prev, pattern_next) # for extracted_text in extracted_text_array: # print(extracted_text) print(' '.join(extracted_text_array))
結果 select owner#,name,namespace,remoteowner,linkname,p_timestamp,p_obj#, nvlp_obj#=obj#(+) order by order#

抽出方法にお詳しい方、実現する為にはどんなコードを書けば条件に一致するすべての値を取得できるでしょうか?
(※本当に初心者です。。googleでもずっと調べていますが解決方法がわかりません。
アイデアやヒントでも構いませんのでコメントいただけるとありがたいです。。)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

can110

2020/07/18 18:15 編集

結果2を除外しているルールはどのようなものでしょうか? また結果3において「200 200 200」を除外しているルールはどのようなものでしょうか?
polpop

2020/07/18 18:41 編集

can110さん ご質問ありがとうございます。 sampleファイルは練習のため単純なものにしていますが、実際は以下のようなカラムが文頭に存在するためとなります。 Elapsed per Exec(s) %total --------- ------------- ------------------- 200    200      200 module: select ~~~~~~~~~~~ from ~~ where 「200 200 200」はそれぞれのカラムに対しての値となります。 そのため、取り出したい値はそれ以下のsqlのみとなります。 最終的には、以下の200 の値もそれぞれのカラムごとに取得したいと考えております。
can110

2020/07/18 18:42

繰り返しになり恐縮ですが ■質問1:結果2を除外しているルールはどのようなものでしょうか? 結果2の「select p_obj#, nvlp_obj#=obj#(+) order by order#」も抽出されるべきと思うのですが。 ■質問2:結果3において「200 200 200」を除外しているルールはどのようなものでしょうか? 結果3において、module:の次の行に「200 200 200」が存在し、その次の行に「select ~」が存在しますが、txtから抽出したい値の②において「200 200 200」が含まれていません。この「200 200 200」を除外するルールを明確に示してほしいということです。
polpop

2020/07/18 18:56 編集

can110 夜分遅くにも関わらずありがとうございます。 以下回答となります。 ■質問1 結果2を除外している理由は”SQL order by psychical time”の結果であるためです。 抽出したいのは”SQL order by Elapsed time”の物ので尚且つmoduleを含む物だけの為となります。。 ■質問2 結果3の「200 200 200」もheader部分の上記で上げたカラムのそれぞれの値を示しているためとなります。 Elapsed per Exec(s) %total --------- ------------- -------------------
can110

2020/07/18 18:56

たずねているのは理由ではなく抽出するためのルール、仕様です。 コンピュータは「結果2を除外している理由は”SQL order by psychical time”の結果である」などといったテキストに書かれた内容、意味を理解できません。そのため、テキストに含まれる文字やその出現位置などのみから抽出するためのルールを決める必要があります。 このルールが明確でないと、問題を解決することは不可能です。
polpop

2020/07/18 19:29 編集

私がイメージしていたルールは以下になります。 1.SQL order by Elapsed timeの結果範囲を抽出(sample.txtの結果1と結果3部分) 2 1で抽出した範囲で"module"の文字列が存在する場合は、module以下のSQL文を抽出 >>テキストに含まれる文字やその出現位置などのみから抽出するためのルールを決める必要があります →"SQL order by Elapsed time"と"module"がこの文字列に該当すると考えておりましたが十分ではないという事でしょうか。。。?
can110

2020/07/18 19:33

1.結果の範囲、開始と終了位置、とくに終了位置がどのようなルールで決まるかが不明確だと思います。 2.抽出したい「SQL文」範囲を特定するルールが不明確だと思います。単純にmodule以下だと「200 200 200」も含まれてしまうことならないでしょうか。
polpop

2020/07/18 19:39 編集

can110さん申し訳ございません。 結果3の「200 200 200」の位置ですが、私の記載ミスでした。。。 修正しました。混乱させてしまい申し訳ございませんでした。
polpop

2020/07/18 19:49 編集

1.結果の範囲、開始と終了位置、とくに終了位置がどのようなルールで決まるかが不明確だと思います。 →実装はできていませんが、結果間の改行を終了位置にできないかと考えておりました。。
can110

2020/07/18 20:12 編集

結果間に必ず改行が1行分入っているのが保証されていればそれでよいかと思われます。 できれば修正依頼欄に書かれたルールを整理して質問本文に記載ください。 そのさい、テキストファイルの内容を何も知らない人間に処理させるためのマニュアルだと仮定して記載してみてください。この「マニュアル」ができて初めてコンピュータにも同じことをさせることができます。
guest

回答2

0

とりあえず挙げられた要件を満たすであろう、できるだけシンプルなルールを考えてコード化しました。
参考まで。

Python

1# ファイルから読込済みのテストデータ 2s = """SQL order by Elapsed time #結果1 3------------------------- 4100 100 100 5module: 6select owner#,name,namespace,remoteowner,linkname,p_timestamp,p_obj#, nvlp_obj#=obj#(+) order by order# 7 8SQL order by psychical time #結果2 9------------------------- 10300 300 300 11module: 12select p_obj#, nvlp_obj#=obj#(+) order by order# 13 14SQL order by Elapsed time #結果3 15------------------------- 16200 200 200 17module: 18select /*+ rule */ bucket_cnt, row_cnt, cache_cnt, null_cnt, timestamp#, sample_ 19size, minimum, maximum, distcnt, lowval, hival, density, col#, spare1, spare2, a 20vgcln, minimum_enc, maximum_enc from hist_head$ where obj#=:1 and intcol#=:2 21 22SQL order by Elapsed time #結果4 23------------------------- 24Elapsed: 25200 200 200 26select ringo ringo ringo 27mikan mikan mikan mikan""" 28 29for result in s.split('\n\n'): # 空行で「結果」ごとに分割 30 if result.startswith('SQL order by Elapsed time'): # 「結果」がこの文字列で始まるもののみ 31 module = result.split('module:') # 「module:」で前後を切り分ける。 32 if len(module) >= 2: 33 sql = module[1] # 後ろが「SQL文」 34 sql = module[1].replace('\n', '') # 複数行の「SQL文」を1行にまとめる 35 print(sql)

投稿2020/07/19 06:09

can110

総合スコア38341

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

要件が複雑なのでクラスを使います:

python

1import re 2 3class Scanner: 4 def __init__(self, pattern_prev, pattern_next): 5 self.pattern_elapsed = re.compile(r"SQL\sorder\sby\sElapsed\stime") 6 self.pattern_prev = re.compile(pattern_prev) 7 self.pattern_next = re.compile(pattern_next) 8 self.extracted_text_array = [] 9 self.is_elapsed = False 10 self.is_extracting = False 11 self.sql = [] 12 13 def scan(self, line): 14 """ 15 状態によって行う処理を切り替えて実行します 16 """ 17 line = line.rstrip() 18 if not self.is_elapsed: 19 self.search_elapsed(line) 20 return 21 if not self.is_extracting: 22 self.search_prev(line) 23 return 24 if self.pattern_next.match(line): 25 self.emit_sql() 26 return 27 self.sql.append(line.rstrip()) 28 29 def search_elapsed(self, line): 30 """ 31 Elapsed stime の行が見つかるまでひたすら読み飛ばします 32 Elapsed stime の行が見つかった場合、読み飛ばしをやめるために状態を変更します 33 """ 34 if self.pattern_elapsed.match(line): 35 self.is_elapsed = True 36 37 def search_prev(self, line): 38 """ 39 pattern_prev の行が見つかるまでひたすら読み飛ばします 40 pattern_prev の行が見つかった場合、読み飛ばしをやめるために状態を変更します 41 """ 42 if self.pattern_prev.match(line): 43 self.is_extracting = True 44 45 def emit_sql(self): 46 """ 47 仮の list に読み貯めた複数行の SQL 文を 1 行文字列に変換して 48 結果の list に追加し、仮の list をクリアします 49 再び Elapsed stime の行が見つかるまでひたすら読み飛ばすために状態をもとに戻します 50 """ 51 self.is_elapsed = False 52 self.is_extracting = False 53 self.extracted_text_array.append(' '.join(self.sql)) 54 self.sql = [] 55 56 57def extract_text_in_file(filepath, pattern_prev, pattern_next): 58 scanner = Scanner(pattern_prev, pattern_next) 59 with open(filepath, "r", encoding="utf-8") as f: 60 for line in f: 61 scanner.scan(line) 62 63 return scanner.extracted_text_array 64 65filepath = 'C:\Users\Desktop\新しいフォルダー\sample.txt' 66 67pattern_prev = r'module:' 68pattern_next = r'^$' 69extracted_text_array = extract_text_in_file(filepath, pattern_prev, pattern_next) 70for extracted_text in extracted_text_array: 71 print(extracted_text)

sample.txtmodule: の文字列が小文字だったので、コードでも module: を小文字にしました

実行結果:

console

1$ python test.py 2select owner#,name,namespace,remoteowner,linkname,p_timestamp,p_obj#, nvlp_obj#=obj#(+) order by order# 3select /*+ rule */ bucket_cnt, row_cnt, cache_cnt, null_cnt, timestamp#, sample_ size, minimum, maximum, distcnt, lowval, hival, density, col#, spare1, spare2, a vgcln, minimum_enc, maximum_enc from hist_head$ where obj#=:1 and intcol#=:2

ポイントは、pattern_next にマッチしたとき break で処理を終わらせずに、
is_extractingFalse にして抽出モードをオフにして、
continue で再びループの初めに戻り、繰り返しを続けることです

投稿2020/07/18 17:45

編集2020/07/19 06:00
y_shinoda

総合スコア3272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

polpop

2020/07/18 19:34 編集

y_shinodaさん 遅い時間にも関わらずご回答いただき本当にありがとうございます。 ご教示いただいたコードを確認させていただきました。 しかしこれでは、"SQL order by Elapsed time"の結果範囲のmoduleを含むsqlだけではなく、 "SQL order by psychical time"の結果範囲のmoduleを含む部分のsqlも取得してしまいます。。。 ※sample.txtの中で出力したいsqlに該当するのは、結果1と結果3の部分となります。 "SQL order by Elapsed time"の結果の中でmoduleを含むのみのsqlを取得する方法はあるのでしょうか?
y_shinoda

2020/07/19 05:31

こちらに返答遅くなりましたが、回答を修正しました
polpop

2020/07/19 05:39 編集

y_shinodaさん ご回答いただきありがとうございます。 完璧な回答を誠にありがとうございます!!(す、すごい。。。。) まだ頂いたコードの理解が追い付いていない部分もありますが、出力は私がイメージしていた物です! 頂いたコードを自分で分析して内容を理解しようと思います。 本当にありがとうございました。
y_shinoda

2020/07/19 06:01

理解がすすみやすいよう、コードに docstring を足しておきました
polpop

2020/07/19 09:14 編集

y_shinodaさん 至れり尽くせり本当にありがとうございます。 もう一つだけ教えて頂きたいのですが、仮に以下の様に一つの結果範囲内に2つのSQLが存在する場合も取得する事は可能でしょうか。。? 最後に私自身勉強の為、大変恐れ入りますがご回答いただけると幸いです。 よろしくお願い致します --------------------------------------------------------------- SQL order by Elapsed time #結果1 ------------------------- 100 100 100 module: select owner#,name,namespace,remoteowner,linkname,p_timestamp,p_obj#, nvlp_obj#=obj#(+) order by order# 999 99 99 module: select ownerasdjd from dhdada #ここも出力したい SQL order by psychical time #結果2 ------------------------- 300 300 300 module: select p_obj#, nvlp_obj#=obj#(+) order by order#
y_shinoda

2020/07/19 09:21

コードを変更する必要があります 今、pattern_next を見つけたら を見つけたら self.is_extracting = False してますけど、それはやめて、 "SQL order by psychical time" が見つかったら self.is_extracting = False にするようにすればいけるような気がします (やってみないとわかりませんが)
polpop

2020/07/19 09:32 編集

y_shinodaさん ご回答いただきありがとうございます。 頂いたヒントを元に自分で改修してみます。 pythonを始めて1か月程度ですが学習がもっと楽しくなりました! 本当に感謝致します! この度はありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問