先日書いた中の Python 標準出力→Java受け取りは、
Javaからプロセス起動で実行するPython と文字列の受け渡し - Oboe吹きプログラマの黙示録
リストを長い正規表現で解析する方法でこれでは、ちょっと効率が悪そうで
汚いコードである。
b' ' などとPython に出力させるのでなく、いっそのこと
Base64 エンコードさせたリストを出力させて Java で読み込んだ方が
スマートで安全だ。
Python 側、util ディレクトリに配置する stdio.py は次のようにする。
# -*- coding: UTF-8 -*- from base64 import b64encode class StdIO: # 標準入力 # escape=True : inputした文字をUnicode文字列に変換してリストにする # 標準入力=Unicode入力を想定(Javaプロセス標準出力から受信する場合はTrueにする) # escape=False : inputした文字を変換なしでリストにする。 # 標準入力=通常 def input(self, escape=True): inlist = [] try: if escape: while True: inp = input('') if inp == '': break inlist.append(inp.encode().decode('unicode-escape')) else: while True: inp = input('') if inp == '': break inlist.append(inp) except EOFError: pass return inlist # リストを標準出力 # escape=True : リスト要素をunicode-escape にエンコードして出力 # code : 出力する文字コード、デフォルト 'utf-8' ユニコード指定は、'unicode-escape' def printList(self, list, base64=False, code='utf-8'): outlist = [] if base64==True: for e in list: data = e.encode(code) outlist.append(b64encode(data).decode()) else: for e in list: data = e.encode(code) outlist.append(data) print(outlist)
Java が呼び出す Python のコード
sample.py
# -*- coding: UTF-8 -*- from util.stdio import StdIO stdio = StdIO() list = stdio.input() # Java に返すリストは、Base64 エンコードする stdio.printList(list, True)
Javaのコード
import org.yipuran.csv4j.CSVParser; import org.yipuran.function.ThrowableConsumer; import org.yipuran.util.process.ScriptExecutor; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken;
Python から受け取った文字列を以下3通りの方法で解析する。
・StringTokenizer での抽出
・org.yipuran.csv4j.CSVParser での抽出・・・1行のCSVとして解析させる方法
・Google gson での抽出・・・JSONのリストとして解析させる方法
StringTokenizer または 1行CSVとして解析する方法は、誰でもすぐに思いつくが、
JSONのリストとして解析させる方法は、なかなか思いつかないであろう。
List<String> list = Arrays.asList("A", "B'B", "C\"", "'\"", "あいうえ1234"); try(ByteArrayOutputStream out = new ByteArrayOutputStream()){ ScriptExecutor.runStream(()->"python sample.py" , ()->list.stream().map(e->Unicodes.encode(e) + "\n").collect(Collectors.toList()) , ThrowableConsumer.of(i->i.transferTo(out)) , (t, e)->{ System.out.println("stderr : " + t ); e.printStackTrace(); }); String response = out.toString(); System.out.println(response); // 解析 System.out.println("====== StringTokenizer による抽出 ========="); List<String> list1 = Collections.list(new StringTokenizer(response.replaceAll("[\r\n]", ""), ",")) .stream() .map(e->e.toString().replaceFirst("^(\\['| {0,1}')", "").replaceFirst("'\\]{0,1}$", "")) .map(e->new String(Base64.getDecoder().decode(e), StandardCharsets.UTF_8)) .collect(Collectors.toList()); list1.stream() .forEach(e->{ System.out.println("[" + e+ "]"); }); System.out.println("====== org.yipuran.csv4j.CSVParser による抽出 ========="); List<String> list2 = new CSVParser().tokenize(response.replaceAll("[\r\n\\[\\]]", "")) .stream() .map(e->e.replaceAll("'", "")) .map(e->new String(Base64.getDecoder().decode(e), StandardCharsets.UTF_8)) .collect(Collectors.toList()); list2.stream() .forEach(e->{ System.out.println("[" + e+ "]"); }); System.out.println("====== Google gson による抽出 ========="); List<String> list3 = new GsonBuilder().serializeNulls().create() .fromJson(response, new TypeToken<List<String>>(){}.getType()); List<String> list4 = list3.stream() .map(e->new String(Base64.getDecoder().decode(e), StandardCharsets.UTF_8)) .collect(Collectors.toList()); list4.stream() .forEach(e->{ System.out.println("[" + e+ "]"); }); }catch(IOException ex){ ex.printStackTrace(); }finally{ }
実行結果は、、、
['QQ==', 'QidC', 'QyI=', 'JyI=', '44GC44GE44GG44GIMTIzNA=='] ====== StringTokenizer による抽出 ========= [A] [B'B] [C"] ['"] [あいうえ1234] ====== org.yipuran.csv4j.CSVParser による抽出 ========= [A] [B'B] [C"] ['"] [あいうえ1234] ====== Google gson による抽出 ========= [A] [B'B] [C"] ['"] [あいうえ1234]