'20/08/13更新:見づらかったので記事構成を編集しました。
本コードの仕様について説明します。下図左にある「@TARGET_*@」のように@で囲まれた複数箇所を下図右のように置換する雛形コードを載せました。複数行に渡って置換している元データは、別ファイルからpandasを用いて抽出後、加工して置換します。
具体例を示します。下図4つのファイルを作成します。
▼ファイル①「abc.txt」
置換対象のファイルです。@で囲まれた箇所を置換します。
aaa hhhhhhhhhhhhhhhhhh 22222222 ################################### @TARGET_2@ ################################### @TARGET_3@ @TARGET_1@ end
▼ファイル②「dataA.csv」
置換するデータです。ここから指定データをpandasで抽出します。
No,Property,Material 1,IS1,Cu 2,GF1_2,Ag 3,NT1_2,Au 4,GF1_3,Ag 5,GF1_1,Ag 6,NT1_1,Au 7,GF1_5,Ag 8,GF1_4,Ag 9,NT1_4,Au 10,IS2,Cu 11,GF2_2,Ag 12,NT2_2,Au 13,GF2_3,Ag 14,NT2_3,Au 15,GF2_1,Ag 16,NT2_1,Au 17,GF2_5,Ag 18,NT2_5,Au 19,GF2_4,Ag 20,NT2_4,Au 21,IS3,Cu
▼ファイル③「dataB.csv」
置換するデータです。ここから指定データをpandasで抽出します。
name,x_min,x_max,y_min,y_max,z_min,z_max A1,0,0.3,0.15,0.15,-0.1,0.1 A2,0,0.3,0.15,0.15,0.2,0.4 A3,0,0.3,0.15,0.15,0.5,0.7 B1,0,0.3,-0.15,-0.15,-0.1,0.1 B2,0,0.3,-0.15,-0.15,0.2,0.4 B3,0,0.3,-0.15,-0.15,0.5,0.7
▼ファイル④「replace.py」
本体プログラムです。例えば、コマンドプロンプトでカレントディレクトリへ移動して「python replace.py」と実行すれば、冒頭の図のように置換した結果ファイルを得られます。
■本プログラム
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os, sys, shutil import pandas as pd def myComment(): buf=[] # 空のリスト(配列)を作成 buf.append('fruits' + '\n') # appendメソッドでリストに要素を追加する buf.append(' orange' + '\n') buf.append(' apple' + '\n') buf.append(' grape' + '\n') return buf class Extract_dataA: def __init__(self, data_file): # インスタンス生成時に呼び出される。コンストラクタ self.df = pd.read_csv(data_file, header=0) # pandas data frame' # header=0は一行目のことでdefaultで書かなくても可 print('self.df -> ' + str(self.df)) def select_columndata(self, select_column, extract_name): # 指定列に指定した文字列がある行データを全て抽出 select_df = self.df[self.df[select_column]==extract_name] return select_df def sort_columndata(self, DF, sort_column): # 指定列を基準にソート(並び替え)する sort_df = DF.sort_values(sort_column, ascending=True) return sort_df def extra_columndata(self, DF, extract_name, extract_column): # 指定列のデータを下記フォーマットへ代入してリスト化 columnlist = DF[extract_column].values.tolist() print('columnlist -> ' + str(columnlist)) buf=[] buf.append('dataset '+ str(dict[extract_name]) + '=[') for i in range(len(columnlist)): if (i < len(columnlist)-1): buf.append('\"' + extract_column + str(columnlist[i])+'\",') else: buf.append('\"' + extract_column + str(columnlist[i])+'\"') buf.append(']' + '\n') return buf class Extract_dataB: def __init__(self, data_file): # インスタンス生成時に呼び出される。コンストラクタ self.df = pd.read_csv(data_file, header=0, index_col=0) # pandas data frame' print('self.df -> ' + str(self.df)) self.indexlist = self.df.index.values.tolist() # インデックス名をリスト化 print(self.indexlist) def data_set(self): buf=[] for i in range(len(self.indexlist)): tmplist=[] tmplist=self.df.loc[str(self.indexlist[i])].values.tolist() # 各インデックスの行データをリスト化 buf.append('func(name=' +str(self.indexlist[i]) + ',\n') buf.append(' x_min='+str(tmplist[0])+ ', x_max=' +str(tmplist[1])+ ',\n') buf.append(' y_min='+str(tmplist[2])+ ', y_max=' +str(tmplist[3])+ ',\n') buf.append(' z_min='+str(tmplist[4])+ ', z_max=' +str(tmplist[5])+ ')\n') return buf def create_file(replace_set, replace_list): tmp_list=[] flag=0 with open(replace_set[0], "r") as f1: k=0 for row in f1: if row.find(replace_set[2]) != -1: flag = k print('flag -> ' + str(flag)) tmp_list.append(replace_list) print(tmp_list[flag]) else: tmp_list.append(row) k=k+1 if replace_set[0]==replace_set[1]: # 入力ファイル名と出力ファイル名を同じに指定した場合。上書きエラーを回避 os.remove(replace_set[0]) with open(replace_set[1], "w") as f2: for i in range(len(tmp_list)): if i != flag: f2.write(str(tmp_list[i])) # 文字列を書く場合 else: f2.writelines(tmp_list[i]) # リストの各要素を全て書き出す場合。ちなみに、要素毎に改行する場合は各要素に改行コードを入れる必要あり。 if __name__ == "__main__": # inputfile, outfile, target_sentence replace_set1 = ('abc.txt', 'abc2.txt', '@TARGET_1@') replace_set2 = ('abc2.txt', 'abc3.txt', '@TARGET_2@') replace_set3 = ('abc3.txt', 'abc4.txt', '@TARGET_3@') replace_list1 = myComment() replace_list2 = [] data_file = 'dataA.csv' select_column = 'Material' extract_name = ['Au','Ag','Cu'] dict={"Au":'gold', "Ag":'silver', "Cu":'bronze'} extract_column = 'No' sort_column = 'Property' for i in range(len(extract_name)): myInstanceA = Extract_dataA(data_file) # インスタンスの生成 mydf1 = myInstanceA.select_columndata(select_column, extract_name[i]) # メソッドの実行 print(mydf1) mydf2 = myInstanceA.sort_columndata(mydf1, sort_column) # メソッドの実行 print(mydf2) mylist = myInstanceA.extra_columndata(mydf2, extract_name[i], extract_column) # メソッドの実行 print(mylist) replace_list2.extend(mylist) # リストの最後にリストを追加。多重配列(ジャグ配列) print('replace_list2-----------------') print(replace_list2) data_file = 'dataB.csv' myInstanceB = Extract_dataB(data_file) # インスタンスの生成 replace_list3 = myInstanceB.data_set() create_file(replace_set1, replace_list1) create_file(replace_set2, replace_list2) create_file(replace_set3, replace_list3)
本コードに関する特記事項は下記二つです。
1. 置換するためのデータファイルを読み込むために、クラスを二つ用意した。
インデックス(行名)がないcsvファイル等を読み込む用にはクラス「Extract_dataA」。一方のクラス「Extract_dataB」はインデックスを一番左列に指定してcsv等のファイルを読み込む用です。それぞれ、その下に関数(クラスなのでメソッド)を作成していく仕様で、汎用性を考慮したためです。
2. 置換元と置換後のファイル名をinputfile, outputfileで指定できる。
もし、両者を同名で指定すれば、ファイル自体も置換した結果になります。例えば、本コード中の「abc2.txt」「abc3.txt」「abc4.txt」を「abc.txt」にすれば可能です。
以上
<広告>