[Java] 76 カタカナをローマ字に変換 ICU4J

[macOS catalina 10.15.7]

DesktopクラスでHTMLファイルを読み込む際、ファイル名に日本語が含まれているとエラーになります(macOS起因の可能性あり)。その場合はファイル名をエンコードするか、日本語をローマ字に変換して対処します。

調べていたらICU4Jという変換ツールを見つけたのでGitHubからjarファイルをダウンロードして試してみました。C言語版もあります。ICUはInternational Components for Unicodeの略で、このプロジェクトにはMicrosoftの社員が関わっているようです。

注意点としては、長音が含まれるとマクロンという横棒付きになりHTML読み取り時にエラーになります。一旦平仮名に変換してからローマ字に変換すると ā→aa となってうまくいきました。

日本語をエンコードすると意味が分からなくなるので躊躇していましたが、このツールでローマ字化して解決しました。今後も重宝しそうです。

import com.ibm.icu.text.Transliterator;

<中略>

Transliterator transliterator = Transliterator.getInstance("Katakana-Latin");
String name_latin = transliterator.transliterate(name);
System.out.println("競走馬名直接ローマ字 " + name_latin);

Transliterator transliterator2 = Transliterator.getInstance("Katakana-Hiragana");
String name_hira = transliterator2.transliterate(name);
System.out.println("競走馬名ひらがな " + name_hira);

Transliterator transliterator3 = Transliterator.getInstance("Hiragana-Latin");
String name_latin2 = transliterator3.transliterate(name_hira);
System.out.println("競走馬名ローマ字 " + name_latin2);
--------------------------------------------------

出力
--------------------------------------------------
競走馬名直接ローマ字 shafuriyāru
競走馬名ひらがな しゃふりやある
競走馬名ローマ字 shafuriyaaru

[Java] 75 Swing 15 JEditorPaneハイパーリンク・クリック後の動作

EditorPaneのハイパーリンク・クリック後の動作についてコードを追記しました。

リンク先のHTMLファイルは、JavaのクラスあるいはPythonの外部プログラムで作成します。

外部プログラムを使う場合、HTMLファイルのパスを渡すすべがないので、空のHTMLファイルを作成した後、Pythonのglobメソッドとsorted関数でファイルを見つけ出し加工します。

    // PAGE_CENTER設定
		editorPane = new JEditorPane();
		contentPane.add(editorPane, BorderLayout.CENTER);
		editorPane.setContentType("text/html");
		editorPane.setEditable(false);
		editorPane.setBackground(new Color(0xf0f8ff));
		editorPane.addHyperlinkListener(new HyperlinkListener() {
            @Override
            public void hyperlinkUpdate(HyperlinkEvent e) {
		        if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) {
		        	String race_html_pre = e.getURL().toString();
		        	System.out.println("race_html_pre " + race_html_pre);
              
                  // HTMLファイルパスの"file:"を削除
		        	String race_html = race_html_pre.substring(5);
		        	StringBuilder HTMLcode = new StringBuilder();
		        	HTMLcode.append("<table>" + "</table>");
		        	
		        	// 空HTMLファイルの作成
		            try{
		                File file = new File(race_html);
		                FileWriter filewriter = new FileWriter(file);
		                filewriter.write(HTMLcode.toString());
		                filewriter.close();}
		            catch(IOException e0){
		                System.out.println(e0);
		            }

               // ここでリンク先のHTMLファイルを作成する

		            Desktop desktop = Desktop.getDesktop();
		            try {
		                desktop.browse(e.getURL().toURI());
		            } catch (IOException e1) {
		                e1.printStackTrace();
		            } catch (URISyntaxException e1) {
		                e1.printStackTrace();
		            }
		        }
		    }
        });

[Java] 74 Swing 14 JEditorPaneのハイパーリンクHTML作成

前回の続きです。

早速ハイパーリンク付きのHTMLファイルを作成するコードを書きました。

実際はリンク先のHTMLファイルはまだ作られておらず、リンクをクリックすると同時にSQL検索(あるいはSQL登録前の元ファイル検索)してレースHTMLをPythonにて作成します。

出走レース番号を付番するためにJRAの最大出走回数記録を調べたところ、1986年以降生まれではハートランドヒリュの127戦でした。したがってゼロ埋めは3桁に設定しています。

        // ベタ書きHTMLの文字列インスタンスを作成
        StringBuilder HTMLcode = new StringBuilder();

        // 現在日時の文字列インスタンスを作成
        Date dateObj = new Date();
        SimpleDateFormat format = new SimpleDateFormat( "yyMMddHHmmss" );
        String now = format.format( dateObj );

        // 競走馬名を取得
        String name = nameAndID4.get(0);
        System.out.println("競走馬名 " + name);

        Integer count = 0;
        HTMLcode.append("<table" + " " + "border='1'" + " " + "class='dataframe'>" + "<thead><tr>");
        for (ArrayList<String> raceList: raceListConSorts){
            if (count == 0){
                for (int i = 0 ; i < raceList.size() ; i++){
                    HTMLcode.append("<th>" + raceList.get(i) + "</th>");}
                HTMLcode.append("</tr></thead><tbody>");
                HTMLcode.append("<tr>");
                count = count + 1;}

            else{
                for (int i = 0 ; i < raceList.size() ; i++){
                	if (i == 4) {
                		String race_html = String.format("/%s_%s_%03d.html",now,name,count);
                		HTMLcode.append("<td>");
                		HTMLcode.append("<a href='" + race_html + "'>" + raceList.get(i) + "</a>");
                		HTMLcode.append("</td>");
                	}
                	else {
                    HTMLcode.append("<td>" + raceList.get(i) + "</td>");
                    }
                }
                HTMLcode.append("</tr>");
                count++;
            }
        }
        HTMLcode.append("</tbody></table>");

        // HTMLファイル名を作成
        String filename = String.format("/%s_%s.html",now,name);

        // HTMLファイルの作成
        try{
            File file = new File(filename);
            FileWriter filewriter = new FileWriter(file);
            filewriter.write(HTMLcode.toString());
            filewriter.close();}
        catch(IOException e){
            System.out.println(e);
        }

[Java] 73 Swing 13 JEditorPaneにおけるハイパーリンク設定

JEditorPaneにおけるハイパーリンク設定を以下に記します。ハイパーリンクをクリックすると、ブラウザにリンク先の内容が表示されます。

仕組みができてしまえば、あとはhrefを仕込んだhtmlファイルを作るようにしていくわけですが、新たにリンク先htmlファイルも作らないといけないですし、作業量はそれなりです。

検索時にリンク先htmlを出走全レース作るフローにするとその分処理時間が長くなるため、ハイパーリンクをクリックするタイミングでSQL検索しリンク先htmlを作成するようにしたいところです。

一連の処理は[Java] 68の記事に書いた外部プログラムを拡充してPythonにさせるつもりです。

    // PAGE_CENTER設定
		editorPane = new JEditorPane();
		contentPane.add(editorPane, BorderLayout.CENTER);
		editorPane.setContentType("text/html");
		editorPane.setEditable(false);
		editorPane.setBackground(new Color(0xf0f8ff));
		editorPane.addHyperlinkListener(new HyperlinkListener() {
            @Override
            public void hyperlinkUpdate(HyperlinkEvent e) {
		        if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) {
		            Desktop desktop = Desktop.getDesktop();
		            try {
		                desktop.browse(e.getURL().toURI());
		            } catch (IOException e1) {
		                e1.printStackTrace();
		            } catch (URISyntaxException e1) {
		                e1.printStackTrace();
		            }
		        }
		    }
        });

[Java] 72 Swing 12 JEditorPane・HTML要素からのリンク可否

JEditorPane内のテキストからのリンクはできるようですが、HTML要素からのリンクが可能なのかどうかは不明のため検証してみました。

これが可能であればレース名をクリックして、レース結果を表示できたりします。

検証の結果、aタグが最上層でなくてもハイパーリンクが可能なことが分かりました。ただしリンク先アドレスに日本語が含まれる場合、事前にエンコードしておく必要があります。

    <tr>
        <td>1999-09-12</td>
        <td>4回阪神2日目</td>
        <td>天候 : 晴</td>
        <td>6 R</td>
        <td>
          <a href="/test.html">
              3歳新馬
          </a>
        </td>
        <td>4</td>
        <td>4</td>
        <td>2.2</td>
        <td>2</td>
        <td>2</td>
        <td>福永祐一</td>
        <td>53.0</td>
        <td>ダ右1400m</td>
        <td>ダート : 良</td>
        <td>1:26.6</td>
        <td>1-1</td>
        <td>37.9</td>
        <td>450(0)</td>
        <td>マチカネラン</td>
        <td>240.0</td>
        <td>r199909040206</td>
   </tr>

[Java] 71 Swing 11 レイアウト設定

Java-Swingアプリのレイアウトを調整しました。

全体:BorderLayout
  PAGE_START:FlowLayout
  CENTER:JEditorPane
  EAST:BorderLayout
  PAGE_END:FlowLayout

GridBagLayoutなどでボタンの位置を細かく設定したいところですが、今はやめておきます。

ボタンの背景色、前景色以外の部分について色設定できず困っています。この形状のボタンでは厳しいのでしょうか。

[Java] 70 Swing 10 PythonによるCSVファイル集計 距離着別度数

芝とダートの距離着別度数を表示させました。

<該当箇所のみ>

# 距離着別度数
list_コース = df['コース'].tolist()

list_距離 = list()
for コース in list_コース:
    距離 = re.sub("\\D", "", コース)
    list_距離.append(int(距離))

listT1_order = list() # 芝1400m未満
listT2_order = list() # 芝1400-1699m
listT3_order = list() # 芝1700-2099m
listT4_order = list() # 芝2100-2499m
listT5_order = list() # 芝2500m以上

listD1_order = list() # ダ1400m未満
listD2_order = list() # ダ1400-1699m
listD3_order = list() # ダ1700-2099m
listD4_order = list() # ダ2100m以上

for 距離,コース,着順 in zip(list_距離,list_コース,list_着順):
    if "芝" in コース:
        if 距離 < 1400:
            listT1_order.append(着順)
        elif 1400 <= 距離 < 1700:
            listT2_order.append(着順)
        elif 1700 <= 距離 < 2100:
            listT3_order.append(着順)
        elif 2100 <= 距離 < 2500:
            listT4_order.append(着順)
        else:
            listT5_order.append(着順)
    else:
        if 距離 < 1400:
            listD1_order.append(着順)
        elif 1400 <= 距離 < 1700:
            listD2_order.append(着順)
        elif 1700 <= 距離 < 2100:
            listD3_order.append(着順)
        else:
            listD4_order.append(着順)

# 芝1400m未満
着順1_T1 = len([i for i in listT1_order if i == 1])
着順2_T1 = len([i for i in listT1_order if i == 2])
着順3_T1 = len([i for i in listT1_order if i == 3])
着順外_T1 = len([i for i in listT1_order if i > 3])

着別度数_T1 = f"{着順1_T1}-{着順2_T1}-{着順3_T1}-{着順外_T1}"
print("着別度数_T1 " + 着別度数_T1)

<以下略>

[Java] 69 Swing 09 PythonによるCSVファイル集計 条件毎の着別度数

芝とダートの着別度数を算出し、プロフィール隣のJTextAreaに表示しました。あと馬場状態や距離の着別度数は必須でしょう。

芝とダートで活躍した実力馬といえばホクトベガですが地方競馬のデータがこちらにないので、中央の芝とダートにデータがあるナリタハヤブサを検索例にしました。ここまで書いたところでアグネスデジタルを思い出しました。

import glob,csv
import pandas as pd

paths = glob.glob('/*.csv')
print(paths)

paths2 = sorted(paths)
print(paths2)

csvfile = paths2[-1]
print(csvfile)

df = pd.read_csv(csvfile,encoding='UTF-8')
print(df)

prize = df['賞金'].sum(skipna=True).round(1)
print(f"獲得賞金 {prize}")

race_count = len(df)
print("レース数 " + str(len(df)))

list_着順 = df['着順'].tolist()
着順1 = len([i for i in list_着順 if i == 1])
着順2 = len([i for i in list_着順 if i == 2])
着順3 = len([i for i in list_着順 if i == 3])
着順外 = len([i for i in list_着順 if i > 3])

着別度数 = f"{着順1}-{着順2}-{着順3}-{着順外}"
print("着別度数 " + 着別度数)

list_馬場 = df['馬場状態'].tolist()

list_turf_order = list()
list_dirt_order = list()
for course,order in zip(list_馬場,list_着順):
    if "芝" in course:
        list_turf_order.append(order)
    else:
        list_dirt_order.append(order)

着順1_t = len([i for i in list_turf_order if i == 1])
着順2_t = len([i for i in list_turf_order if i == 2])
着順3_t = len([i for i in list_turf_order if i == 3])
着順外_t = len([i for i in list_turf_order if i > 3])

着別度数_t = f"{着順1_t}-{着順2_t}-{着順3_t}-{着順外_t}"
print("芝着別度数 " + 着別度数_t)

着順1_d = len([i for i in list_dirt_order if i == 1])
着順2_d = len([i for i in list_dirt_order if i == 2])
着順3_d = len([i for i in list_dirt_order if i == 3])
着順外_d = len([i for i in list_dirt_order if i > 3])

着別度数_d = f"{着順1_d}-{着順2_d}-{着順3_d}-{着順外_d}"
print("ダ着別度数 " + 着別度数_d)

list_output = [{"獲得賞金":prize,"着別度数":着別度数,"芝":着別度数_t,"ダ":着別度数_d}]

# 出力ファイル名作成
filename = csvfile.split(".")[0] + "_agg.csv"

field_name = ['獲得賞金','着別度数','芝','ダ']
with open(filename,'w',encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames = field_name)
    writer.writeheader()
    writer.writerows(list_output)

[Java] 68 Swing 08 外部プログラムの選択 改良版

前回の続きです。switch文の重複部分が気になったので書き直しました。こちらの方がメンテナンス性も優れており断然スマートです。

import java.util.ArrayList;

public class ProcessExecutor {
    public static void exec(String type) throws Exception {
    	System.out.println("ProcessExecutor");

    	// 分類用リスト作成 集計:agg,分析:ana,血統:blo 以降随時追加
    	ArrayList<String> types = new ArrayList<String>();
    		types.add("agg");
    		types.add("ana");

		// cmdリスト作成
		ArrayList<String> cmds = new ArrayList<String>();
    		cmds.add("python HS_csv_agg.py ; echo 'コマンド完了'");
    		cmds.add("python HS_csv_ana.py ; echo 'コマンド完了'");

    	// index番号取得
    	int type_num = types.indexOf(type);
    	System.out.println("index番号 " + type_num);

    	// コマンド選択
    	String cmd = cmds.get(type_num);

		ProcessBuilder p = new ProcessBuilder("sh", "-c", cmd);
        p.redirectErrorStream(true);
        // プロセス開始
        Process process = p.start();
        // プロセス終了まで待機
        process.waitFor();
        int result = process.exitValue();
        System.out.printf("result = %d%n", result);
    }
}

[Java] 67 Swing 07 外部プログラムの選択(switch文)

Java-Swingアプリの集計、分析等はPythonで処理していますが、処理内容によってコードを使い分けるようにしました。

import java.util.ArrayList;

public class ProcessExecutor {
    public static void exec(String type) throws Exception {
    	System.out.println("ProcessExecutor");

    	// 分類用リスト作成 集計:agg,分析:ana,血統:blo 以降随時追加
    	ArrayList<String> types = new ArrayList<String>();
    		types.add("agg");
    		types.add("ana");
    		types.add("blo");

    	// case番号を付番
    	int type_num = types.indexOf(type);
    	System.out.println("case番号 " + type_num);

    	switch(type_num) {
			case 0: // 集計
				String cmd0 = "python HS_csv_agg.py ; echo 'コマンド完了'";
				ProcessBuilder p0 = new ProcessBuilder("sh", "-c", cmd0);
		        p0.redirectErrorStream(true);
		        // プロセス開始
		        Process process0 = p0.start();
		        // プロセス終了まで待機
		        process0.waitFor();
		        int result = process0.exitValue();
		        System.out.printf("result = %d%n", result);
		        break;
			case 1: // 分析
				String cmd1 = "python HS_csv_ana.py ; echo 'コマンド完了'";
				ProcessBuilder p1 = new ProcessBuilder("sh", "-c", cmd1);
		        p1.redirectErrorStream(true);
		        // プロセス開始
		        Process process1 = p1.start();
		        // プロセス終了まで待機
		        process1.waitFor();
		        int result1 = process1.exitValue();
		        System.out.printf("result = %d%n", result1);
		        break;
    	}
    }
}