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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

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

Q&A

解決済

2回答

2637閲覧

クリップボードにある文字列のうち、{}で囲まれたものを、辞書から検索し、置換したい

H.K2

総合スコア88

Python 3.x

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

1グッド

3クリップ

投稿2018/06/10 09:41

【やりたいこと】
pythonを用いて、クリップボードに入った文字列のうち、{}で囲まれたものを、
置換用の辞書にあるキーと一致した場合に、値の文字列に一斉に置換するプログラムを作りたいと思っています。

(例)
辞書ファイル(rep_dict.txt)
郵便番号,〒100-8111
住所,東京都千代田区千代田1-1
宛先指名,山田 太郎
案件,H社向け××システム

クリップボードの文字:
{宛先指名}様
先月ご依頼いただきました{案件}についてですが、…(中略)

以下住所に書類を送付いただけませんでしょうか。
{郵便番号} {住所} 宛

お忙しい中大変申し訳ありませんが、ご対応のほど、よろしくお願いいたします。

【やってみたこと】
下記コードを描いてみました。

python3

1import pyperclip, re, threading, random 2 3def task(): 4 copy_text = str(pyperclip.paste()) 5 6 #todo:ここで読み込む。下はテストで置き替え。{}で囲まれた文字は****で置き換えはできた 7# new = re.sub(r'{.+}', '****', copy_text) 8 9 if len(copy_text) > 0: 10 pyperclip.copy(''.join(new)) 11# print('---Rewrite Complete!---') 12 else: 13 print('---Failure---') 14 th = threading.Timer(5, task) 15 th.start() 16 17t = threading.Thread(target=task) 18t.start() 19 20 21

上記のコードで、定期的に{}内の文字を****に置換するのには成功したのですが、
辞書を読み込んで、その情報と一致したら置換する処理を描こうとして詰まってしまいました。

下記のコードを追加したら、辞書を読み込む際に、エラーが出てしまいました。

with open("rep_dict.txt") as f:
s = f.read()
print(s)
dict_rep = dict(line.strip().split(',') for line in s)
dict_rep

ValueError: dictionary update sequence element #0 has length 1; 2 is required

もしよろしければ、よい解決策についてご教示いただければと考えます。

yohhoy👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

エラーの原因

下記のコードを追加したら、辞書を読み込む際に、エラーが出てしまいました。

Python

with open("rep_dict.txt") as f:
s = f.read()
print(s)
dict_rep = dict(line.strip().split(',') for line in s)
dict_rep

ValueError: dictionary update sequence element #0 has length 1; 2 is required

期待に反して、lineに各行が与えられていないからです。

Python

1print([line for line in s]) # => ['郵', '便', '番', '号', ',', '〒', '1', '0', '0', '-', '8', '1', '1', '1', '\n', '住', '所', ',', '東', '京', '都', '千', '代', '田', '区', '千', '代', '田', '1', '-', '1', '\n', '宛', '先', '指', '名', ',', '山', '田', '\u3000', '太', '郎', '\n', '案', '件', ',', 'H', '社', '向', 'け', '×', '×', 'シ', 'ス', 'テ', 'ム']

次のように書けば良いです。

Python

1dict_rep = dict(line.strip().split(',') for line in s.split('\n'))

また、さらに簡潔にも書けます。

Python

1with open("rep_dict.txt") as f: 2 # s = f.read() 3 # print(s) 4 dict_rep = dict(line.strip().split(',') for line in f) 5 print(dict_rep)

書いてみた

面白そうなので、ちょっと書いてみました。

Python

1from collections import defaultdict 2import re 3 4# 5# 本当はjsonで扱いたいところ 6rep_dict = defaultdict(str) 7with open(r'rep_dict.txt') as f: 8 for row in f: 9 row = row.strip() 10 key, value = row.split(',') 11 rep_dict[key] = value 12 13# 14# 15def my_replace(match): 16 key = match.group().strip('{}') 17 return rep_dict[key] 18 19src = open(r'clipboard.txt').read() 20dst = re.sub(r'{.+?}', my_replace, src) 21 22print(dst)

実行結果 Wandbox

plain

1山田 太郎様 2先月ご依頼いただきましたH社向け××システムについてですが、…(中略) 3 4以下住所に書類を送付いただけませんでしょうか。 5〒100-8111 東京都千代田区千代田1-1 宛 6 7お忙しい中大変申し訳ありませんが、ご対応のほど、よろしくお願いいたします。

何かご不明な点があれば、お気軽にお尋ねください。

投稿2018/06/10 10:02

編集2018/06/10 10:11
LouiS0616

総合スコア35660

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

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

H.K2

2018/06/10 14:23

迅速なご回答ありがとうございます! なるほど、、[line for line in s]だと1文字ずつになってしまうのですね…。 [line for line in s.split('\n'))]のように改行コードをつかって分割するときちんと取得できるのはなぜなのでしょうか…。基本的な質問で申し訳ありません。。。
LouiS0616

2018/06/10 14:26

前者は、文字列そのものに対してループしようとしています。 後者は、文字列を改行文字で分割したリストに対してループしようとしているのです。
H.K2

2018/06/10 14:33

ああなるほど…。文字列扱いで、1文字ずつループになるけど、 リストに対してのループなら、その分割後の要素に対してのループになるのですね、、ありがとうございます!
guest

0

おもしろいプログラムですね。変換テーブルのファイルを読み込むのは LouiS0616 さんが解説なさっている通りです。CSVであれば csv モジュールを使うのがおすすめですが。

今回のように { ほげほげ } のような決められた記法で書かれたテキストに別の文字列を埋め込む仕組みを「テンプレート」と呼びます。Python では Jinja2 という大変有名なテンプレートエンジンがあります。自前で {…} を検索して文字を入れていってもよいですが、テンプレートエンジンを使うことによってより簡単に、より正確に、そしてより柔軟な事ができるようになります。

以下サンプルで書いてみました。

python

1import csv 2import time 3 4from jinja2 import Environment 5import pyperclip 6 7 8if __name__ == '__main__': 9 with open("rep_dict.txt") as f: 10 reader = csv.reader(f) 11 dict_rep = {row[0]: row[1] for row in reader} 12 13 clip_last = None 14 while True: 15 clip = pyperclip.paste() 16 if clip != clip_last: 17 print('--- Clipboard changed ---') 18 new_clip = Environment().from_string(clip).render(dict_rep) 19 if clip != new_clip: 20 pyperclip.copy(new_clip) 21 print('--- Rewrite Complete! ---') 22 clip_last = new_clip 23 time.sleep(1)

text

1{{ 宛先指名 }}様 2先月ご依頼いただきました{案件}についてですが、…(中略) 3 4以下住所に書類を送付いただけませんでしょうか。 5{{ 郵便番号 }} {{ 住所 }} 宛 6 7お忙しい中大変申し訳ありませんが、ご対応のほど、よろしくお願いいたします。

↑ Jinja2 では変数の埋め込みに {{ 変数名 }} という記法を使います。


次に応用編です。テンプレートエンジンを使うとより柔軟にテキストを生成することができます。

json

1{ 2 "郵便番号": "〒100-8111", 3 "住所": "東京都千代田区千代田1-1", 4 "宛先指名": "山田 太郎", 5 "案件": "H社向け××システム", 6 "必要書類": [ 7 "見積もり確認書", 8 "要求案件シート", 9 "仮契約書" 10 ] 11}

python

1import json 2import time 3 4from jinja2 import Environment 5import pyperclip 6 7 8if __name__ == '__main__': 9 with open('rep_dict.json', 'r', encoding="utf-8") as f: 10 dict_rep = json.load(f) 11 12 clip_last = None 13 while True: 14 clip = str(pyperclip.paste()) 15 if clip != clip_last: 16 print('--- Clipboard changed ---') 17 new_clip = Environment().from_string(clip).render(dict_rep) 18 if clip != new_clip: 19 pyperclip.copy(new_clip) 20 print('--- Rewrite Complete! ---') 21 clip_last = new_clip 22 time.sleep(1)

text

1{{ 宛先指名 }}様 2先月ご依頼いただきました{案件}についてですが、…(中略) 3 4書類を送付いただけませんでしょうか。 5 6送付先: 7{{ 郵便番号 }} {{ 住所 }} 宛 8 9送付書類: 10{% for 書類名 in 必要書類 %}・{{ 書類名 }} 11{% endfor %} 12以上{{ 必要書類|length }}点 13 14お忙しい中大変申し訳ありませんが、ご対応のほど、よろしくお願いいたします。

text

1山田 太郎様 2先月ご依頼いただきました{案件}についてですが、…(中略) 3 4書類を送付いただけませんでしょうか。 5 6送付先: 7〒100-8111 東京都千代田区千代田1-1 宛 8 9送付書類: 10・見積もり確認書 11・要求案件シート 12・仮契約書 13 14以上3点 15 16お忙しい中大変申し訳ありませんが、ご対応のほど、よろしくお願いいたします。

↑ このようにデータが複数ある場合でも対応できますし、要素の数を計算したりと様々な処理が可能です

Jinja2 はWebアプリケーションでHTMLを生成したり、メールの定型文を作ったりなど、動的にテキストを生成する用途に広く使えます。覚えて損はありませんのでぜひ触ってみて下さい。

投稿2018/06/10 11:21

編集2018/06/10 11:48
miyahan

総合スコア3095

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

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

H.K2

2018/06/10 14:24

ありがとうございます! なるほど、jinja2という便利なライブラリがあるんですね…。 テンプレートエンジン、ですか…。非常に便利そうなので、ちょっとググって使えるようにしてみます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問