[Python] 268 ゼロ埋め数字のリストを作成する その2

前回の続きです。

for文ではなくリスト内包表記で書くと以下の通りになります。

リストを関数の戻り値にすることもできますが、普通に変数にする方が使い勝手は良さそうです。

# 00001から11000までの千番台ごとのリストを入れ子にしたリストを作成する関数
def list_num():
    return [[str(x).zfill(5) for x in range(1000*thou +1,1000*thou +1001)]\
for thou in range(0,11) ]

list_num_flat = [y for x in list_num() for y in x]

print(len(list_num_flat))
--------------------------------------------------

出力
--------------------------------------------------
11000

[Python] 267 ゼロ埋め数字のリストを作成する

00001から11000のゼロ埋め数字を1000個ずつまとめたリストの作成コードです。欠番検索の元データに使えます。

リスト内の1つ目のリストは00001から01000のゼロ埋め数字で構成されています。

list_all = list()
for thousand in range(0,11,1):
    list_thou = list()
    for num in range(1,1001,1):
        number = 1000*thousand + num
        # 数字を5桁のゼロ埋め数字に変換する
        number_5digits = str(number).zfill(5)
        list_thou.append(number_5digits)
    list_all.append(list_thou)

# リストを平滑化して入れ子をなくす
list_all_flat = [y for x in list_all for y in x]

print(len(list_all_flat))
--------------------------------------------------

出力
--------------------------------------------------
11000

[Python] 266 globによるパス一覧からの選別

久しぶりにPythonをいじりました。最近は融通の効かないJavaを使いこなすことにやりがいを感じていましたが、Pythonの自由さもいいものです。

globメソッドで得られたCSVファイルのパス一覧から、ファイル内容が条件に合致するパスのリストを作成しようとしたところ、エラーになってしまう問題にぶつかりました。さすがにそこまで柔軟ではないようです。

仕方ないのでパスをprint関数でtxtファイルに追記出力しました。

# 競走馬個別ファイル内の競走馬名が幼名("XXXの2018"など)になっているファイルのパスリストを作成
import glob,os,re,sys
import pandas as pd

print("検索する年度を入力してください")
year = input()

path = f'/horse/{year}'
print(os.listdir(path))

# 数字が含まれているディレクトリ名をリスト化する
pattern = r'\d'
list_dir = [p for p in os.listdir(path) if re.compile(pattern).search(p)]
print(list_dir)

for dir in list_dir:
    for path in glob.glob(f'/horse/{year}/{dir}/*.csv'):
        df = pd.read_csv(path,header = None,encoding='shift_jis')
        
        # B1セル相当の文字列に数字が含まれている場合、ファイルパスを追記出力する
        if re.compile(pattern).search(df.iat[0,1]):
            print(df.iat[0,1])
            with open('未登録馬path.txt', 'a') as f:
                print(path, file = f)
                # list.append(path)は不可なのでこのような処理になった

[Java] 47 Swing 03 getActionCommand

ボタンを押した時のアクションについてコードを書き、完成させました。

とりあえずバージョン0.1が出来上がったので、これから少しずつ機能を増やしていきます。

ガワ(GUI部分)はEclipseのサポートで何とかなりそうですし、アプリ機能を正確かつスムーズにコーディングするスキルを磨いていきたいです。

<途中から>

@Override
	public void actionPerformed(ActionEvent e) {
		String cmd = e.getActionCommand();
		
		if (cmd.equals("Button1")){
			String name = text1.getText();
			
			System.out.println("競走馬名取得 " + name);
			
			Horse.IDSearch(name);
			ArrayList<String> nameAndIDCon = Horse.IDSearch(name);
	    	
			Integer count = nameAndIDCon.size()-1;
	      	    	
	    	StringBuilder result = new StringBuilder();
	    	for (String ele:nameAndIDCon) {
	    		result.append(ele);
    		}
	    	
	    	String resultStr = result.toString();
			area.append(resultStr + "\n");
			
			if (count >= 2) {
				area.append("\n" + "該当する馬が複数います。番号を入力してください。");
				nameAndIDCon.subList(0,1).clear();
				area.append("\n" + nameAndIDCon + "\n");
				
	            int i = 1;
	            for (String s : nameAndIDCon) {
	            	area.append(i + "  " + s + "\n");
	                i = i + 1;
                }
            }
	        else if (count == 0){
	        	area.append("該当する馬はいません"+ "\n");
        	}
	        else {
	            String name2 = nameAndIDCon.get(0);
	            String ID = nameAndIDCon.get(1);

	            area.append(name2 + "のIDは" + ID + "です"+ "\n");
	    
	    		ArrayList<ArrayList<String>> raceList = Horse.raceSearch(nameAndIDCon);
	            ArrayList<ArrayList<String>> raceListCon = Horse.raceSearch2(raceList);
	            Horse.toHTML(raceListCon,nameAndIDCon);
	            
              // HTMLファイルのパスを取得しJEditorPaneに埋め込む
	            path = HTMLPath.main();
	            System.out.println(path);
	            	            
	    		try {
	    			editorPane.setPage(new File(path).toURI().toURL());
	            }
	    		catch (IOException e1) {
	    			e1.printStackTrace();
	    		}
            }
		}
		else if (cmd.equals("Button2")){
			String text3 = text2.getText();
	    	System.out.println(text3);
	    	
	    	int numID = Integer.parseInt(text3);
	    	System.out.println(numID);
	    	
	    	String name3 = text1.getText();
	    	System.out.println(name3);
	    	
	    	ArrayList<String> nameAndIDCon = Horse.IDSearch(name3);
	    	String ID =  nameAndIDCon.get(numID);
	    	ArrayList<String> nameAndIDCon2 = new ArrayList<String>();
	    	nameAndIDCon2.add(name3);
	    	nameAndIDCon2.add(ID);
	    	
	    	ArrayList<ArrayList<String>> raceList = Horse.raceSearch(nameAndIDCon2);
	        ArrayList<ArrayList<String>> raceListCon = Horse.raceSearch2(raceList);
	        Horse.toHTML(raceListCon,nameAndIDCon2);
	        
	        path = HTMLPath.main();
	        System.out.println(path);
	        
    		try {
    			editorPane.setPage(new File(path).toURI().toURL());
            }
    		catch (IOException e1) {
    			e1.printStackTrace();
    		}
		}
	}
}
※海外レースのデータは含まれていません

[Java] 46 Swing 02 パネルとコンポーネントの配置

contentPaneにパネルとコンポーネントを配置しました。

コンポーネントを左寄せにする方法で少しだけ手間取ったので記録を残しておきます。

SwingはPythonのtkinterに使用感が似ています。ただデザインタブで配置が視覚的にできる分、こちらの方がやや優勢でしょうか。

使い勝手で申し分のないJavaFXが使えないのはつくづく残念です。

あとはボタンアクションを追記し、標準出力をPAGE_ENDに表示させるなどして一応完了となります。

package horse_search;

<importは略>

public class Main extends JFrame {

	private JPanel contentPane;
	private JTextField textField;

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Main frame = new Main();
					frame.setVisible(true);
				}
				catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	public Main() {
		// contentPane設定
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 1500, 750);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);

   // CENTER設定
		JEditorPane editorPane = new JEditorPane();
		contentPane.add(editorPane, BorderLayout.CENTER);
		editorPane.setContentType("text/html");
		try {
			editorPane.setPage(new File("シャフリヤール.html").toURI().toURL());
        }
		catch (IOException e) {
			e.printStackTrace();
		}
		
		// PAGE_START設定
		JPanel panel = new JPanel();
		panel.setLayout(new FlowLayout(FlowLayout.LEFT));
		contentPane.add(panel, BorderLayout.PAGE_START);
		
		JLabel label = new JLabel("競走馬名");
	    JTextField text = new JTextField(20);
	    JButton btnNewButton = new JButton("検索");
	    textField = new JTextField(3);
	    JButton btnNewButton_1 = new JButton("確定");
	    	    
	    panel.add(label);
	    panel.add(text);
	    panel.add(btnNewButton);
		panel.add(textField);
		panel.add(btnNewButton_1);
		
		// PAGE_END設定
		JPanel panel2 = new JPanel();
		panel2.setLayout(new FlowLayout(FlowLayout.LEFT));
		contentPane.add(panel2, BorderLayout.PAGE_END);
		
		JTextArea textArea = new JTextArea(15,30);
		textArea.setLayout(new FlowLayout(FlowLayout.LEFT));
		panel2.add(textArea);

[Java] 45 Swing 01 HTMLファイルの表示

JavaFXでWebページの表示はできたのですが、ローカルHTMLファイルの方がどうしてもできません。

JavaFXよりもさらに古いSwingというツールを使ってみたところ、あっけなく解決しました。

JavaFXで色々試しても打開できず、やはりmacOSではJavaよりもSwiftなのかと半ば諦めていました。

SwingはJava8以前でしか使えませんが、JavaFXが私の手に余るので仕方がないです。

あとは競争馬名を入力するテキストフィールドやボタンを配置して完成です。

2021/8/28追記:SwingはJava9以降でも使えます。勘違いしていました。

package swing;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.io.File;
import java.io.IOException;

import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class Sample extends JFrame {

	private JPanel contentPane;

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Sample frame = new Sample();
					frame.setVisible(true);
				}
				catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	public Sample() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		JEditorPane editorPane = new JEditorPane();
		contentPane.add(editorPane, BorderLayout.CENTER);
		editorPane.setContentType("text/html");
		try {
			editorPane.setPage(new File("シャフリヤール.html").toURI().toURL());
        }
		catch (IOException e) {
			e.printStackTrace();
		}
	}
}

[Java] 44 JavaFX 06 WebViewはJava11では動かず

前回記事でJavaFXにあるWebViewの導入に苦労していることを書きましたが、原因は開発環境にありました。

Catalina起因の文字化けトラブルに巻き込まれた経緯からmacOSに疑いの目を向けていました。かといってWindowsに宗旨替えするわけにもいかず、Javaの学習を中断しSwiftへの移行を真剣に検討していたのですが、どう見ても瑕疵のないネット公開のコードも動かないため、開発環境に問題があるのではと考えました。

検証の手間のかからない順に、Javaのバージョン、OS(Windows機は持っているので)、macOSのバージョンとなるところ、まず始めにJava11からJava8に変えてみたらあっさり解決しました。

macOSを取るか、Java(Windows)を取るかという選択を迫られずに済みましたが、かなり後ろ向きな解決方法なので、将来的には他のGUI作成ツールを検討することになるでしょう。

[Java] 43 JavaFX 05 2画面の表示

同じ画面に検索結果のHTMLを埋め込もうとしましたが、どうにもうまくいかないのでまずは別画面に反映させることにします。

空の別画面を作成してみました。ここから色々試してみます。

なおEclipseのエディタではカッコの色分けができないので閉じカッコは文末から通常の位置に戻しました。波カッコにもだいぶ慣れて違和感がなくなってきました。

package horse_search;
	
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class Main extends Application {
	@Override
	public void start(Stage stage) {
		try {
			stage.setScene(new Scene(new AnchorPane(), 400, 200));
			Parent root = FXMLLoader.load(getClass().getResource("App.fxml"));
			Scene scene = new Scene(root);
			scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
			stage.setScene(scene);
			stage.setTitle("Horse Search");
		
			Stage stage2 = new Stage();
			stage2.initOwner(stage);
			stage2.setScene(new Scene(new AnchorPane(), 800, 600));
			Parent root2 = FXMLLoader.load(getClass().getResource("App2.fxml"));
			Scene scene2 = new Scene(root2);
			scene2.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
			stage2.setScene(scene2);
			stage2.setTitle("検索結果");
			
			stage.show();
			stage2.show();
			
			stage2.setX(stage.getX() + 100);
		  stage2.setY(stage.getY() + 100);
		}
		
		catch(Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		launch(args);
	}
}

[Java] 42 JavaFX 04 Controllerファイルの作成

Javaで初めて作成するGUIアプリの進捗です。

Controllerファイルを作成し、競走馬名から成績を検索してHTMLファイルにまとめるという最低限の機能を持たせました。mySQLの操作については別ファイルに分割して書いています。

Scene Builderでコンポーネントをドラッグ&ドロップで並べられるのは本当に便利です。Pythonのtkinterではコンポーネントの指定にウィジェットinfoを使うのに対し、こちらはIDだけでいいのでかなり楽です。

テキストエリアに自動的にスクロールバーが付くのもいいですね。デザインソフトはみな同じなのかもしれませんが、Adobe XDに操作性が似ていてすぐ馴染みました。

次はHTMLファイルをテキストエリアに貼り付けたような感じにしたいので、これから調査します。

package horse_search;

import java.util.ArrayList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

public class SampleController {
    @FXML
    private TextArea area1;
    @FXML
    private Label label1;
    @FXML
    private Button button1;
    @FXML
    private Button button2;
    @FXML
    private TextField textField1;
    @FXML
    private TextField textField2;
    
    @FXML
    void onButton1Action(ActionEvent event) {
    	String name = textField1.getText();
      
      // Horseクラスの戻り値を変数nameAndIDConに設定
    	ArrayList<String> nameAndIDCon = Horse.IDSearch(name);
    	
      // 変数nameAndIDConは競走馬名とIDのリストになっているのでID数は要素数から1を引いて算出
      Integer count = nameAndIDCon.size()-1;
      
      // 競走馬名とIDを結合させたプレ文字列を作成	    	
    	StringBuilder result = new StringBuilder();
    	for (String ele:nameAndIDCon) {
    		result.append(ele);}
    	
    // area1の先頭に変換した文字列を挿入
    	String resultStr = result.toString();
      area1.insertText(0,resultStr + "\n");
		
      // IDが2つ以上の場合は1つを選ばせる
      if (count >= 2) {
          // 末尾に文字列を挿入するため位置place1を算出
          String text1 = area1.getText();
          Integer place1 = text1.length() - 1;
          area1.insertText(place1,"\n" + "該当する馬が複数います。番号を入力してください。");

          // リストから先頭の競走馬名を削除
       nameAndIDCon.subList(0,1).clear();

          // 末尾に文字列を挿入するため位置place2を算出
          String text2 = area1.getText();
          Integer place2 = text2.length() - 1;
          area1.insertText(place2, "\n" + nameAndIDCon + "\n");
			  
          // 選択肢の作成
          int i = 1;
          for (String s : nameAndIDCon) {
              String text3 = area1.getText();
              Integer place3 = text3.length() - 1;
              area1.insertText(place3,i + "  " + s + "\n");
              i = i + 1;}}
        
        else if (count == 0){
            String text4 = area1.getText();
            Integer place4 = text4.length() - 1;
            area1.insertText(place4,"該当する馬はいません"+ "\n");}
        
        else {
            String name2 = nameAndIDCon.get(0);
            String ID = nameAndIDCon.get(1);
            
            String text5 = area1.getText();
            Integer place5 = text5.length() - 1;
            area1.insertText(place5,name2 + "のIDは" + ID + "です"+ "\n");

            ArrayList<ArrayList<String>> raceList = Horse.raceSearch(nameAndIDCon);
            ArrayList<ArrayList<String>> raceListCon = Horse.raceSearch2(raceList);
            Horse.toHTML(raceListCon,nameAndIDCon);}}
		
    // 該当馬が複数の場合は右のテキストフィールドに番号を入力して確定ボタンを押す。
    @FXML
    void onButton2Action(ActionEvent event) {
    	String text6 = textField2.getText();
    	System.out.println(text6);
    	
      // 文字列を整数に変換
    	int numID = Integer.parseInt(text6);
    	System.out.println(numID);
    	
    	String name3 = textField1.getText();
    	System.out.println(name3);
    	
    	ArrayList<String> nameAndIDCon = Horse.IDSearch(name3);
    	String ID =  nameAndIDCon.get(numID);
    	ArrayList<String> nameAndIDCon2 = new ArrayList<String>();
    	nameAndIDCon2.add(name3);
    	nameAndIDCon2.add(ID);
    	
    	ArrayList<ArrayList<String>> raceList = Horse.raceSearch(nameAndIDCon2);
      ArrayList<ArrayList<String>> raceListCon = Horse.raceSearch2(raceList);
      Horse.toHTML(raceListCon,nameAndIDCon2);}}

[Java] 41 JavaFX 03 Scene Builderの導入 Eclipse編

VScodeでのGUIアプリ製作は一旦見合わせ、Eclipseで進めることにしました。色々試行錯誤しているうちに大分UIにも慣れました。

Scene BuilderでGUI画面を作り、SampleControllerSkeletonの内容をコントローラのjavaファイルに写し、GUIの動作を追記するといった流れを学びました。

GUIアプリとしてはTextFieldに競走馬名を入力し、それを先日作成した競馬DB検索コードに取り込んで成績CSVファイルを作成させました。

とりあえず自分用の手本としてアップしておきます。なんでもない内容ですがここまで結構時間が掛かっています。

時間的イニシャルコストは消費したものの、Pythonのtkinterでの苦労は何だったんだと感じる位、操作性が優れている印象です。

一つのプログラミング言語にこだわるよりも適材適所で使い分けるのがいいみたいです。

import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class Main extends Application {
	@Override
	public void start(Stage primaryStage) {
		try {
			AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("Sample.fxml"));
			Scene scene = new Scene(root);
			scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
			primaryStage.setScene(scene);
			primaryStage.show();}
		catch(Exception e) {
			e.printStackTrace();}}
	
	public static void main(String[] args) {
		launch(args);}}
package horse_search;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

public class SampleController {
  @FXML
    private TextArea area1;

  @FXML
    private Label label1;

  @FXML
    private Button button1;

  @FXML
    private TextField textField1;

  @FXML
    protected void onButton1Action(ActionEvent event) {
        String name = textField1.getText();
        System.out.println(name);
        Horse.main(null,name);}} 	
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.paint.*?>
<?import javafx.scene.effect.*?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="200.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="horse_search.SampleController">
   <children>
      <Label fx:id="label1" layoutX="14.0" layoutY="22.0" text="競走馬名" />
      <TextField fx:id="textField1" layoutX="71.0" layoutY="17.0" prefHeight="27.0" prefWidth="153.0" />
      <Button fx:id="button1" layoutX="231.0" layoutY="17.0" mnemonicParsing="false" onAction="#onButton1Action" prefHeight="27.0" prefWidth="52.0" text="検索" />
      <TextArea fx:id="area1" layoutX="20.0" layoutY="56.0" prefHeight="130.0" prefWidth="260.0" />
   </children>
</AnchorPane>
Scene BuilderのUI