せぐ のページ

Sorry, this page is Japanese only.
このページは(これを読んでいる人にはおわかりの通り)日本語で書かれたページです
このページはWindows11日本語版のFirefoxのみで表示を確認しています

ぼそっ(今日の独り言)

どこまでも文字コードが付きまとう

javaでgradle使ってプログラム作るの第2弾。poiでexcelファイルを作る。

cell.setCellValue("日本語文字列");

ってやったら文字化けした。
poi側で何か文字コード設定があるのかと思ってググるのだけれどあまりヒットしない。日本語フォントを設定すれば文字化けが直るとか書いてあるサイトもあったけれどフォントを指定しても直らない。
しばらく悩んで

System.out.println("日本語文字列");

したらこっちも文字化けした(笑)
そうだった、build.gradle.ktsに

tasks.withType<JavaCompile>().configureEach {
    options.encoding = "UTF-8"
}

って書いてUTF-8でビルドしなきゃならないんだった

引き続き、
Excelのxlsxファイルを読み込んで条件付きで文字色を変更して別ファイルに保存させるプログラムを書こうと四苦八苦。OPCPackageってなんだかわからないけれどpoiのサイトのサンプルのコピペで

OPCPackage pkg = OPCPackage.open(new File("indata.xlsx"));

って書いてファイルを読むと読み出ししたいだけなのにファイルが何か更新されてしまうみたい。結局

XSSFWorkbook wb_r = (XSSFWorkbook) WorkbookFactory.create(new File("indata.xlsx"), null, true);

って書いて解決。create()の3番目の引数がread onlyにするフラグらしい。
でもなんか別ファイルを作って保存ってpoiではセル一つ一つを別ファイルにコピーする必要があるみたいで面倒らしい。poiの新しめのバージョンではメソッド一つでシートごとコピーできたりしないのかな・・・。後で調べてみる。

2024年03月20日 プログラミング雑談

javaでifを使わずにnullじゃなかったら実行する

javaでもC++でも良いのですけれど、コードを書いているとnullチェックのif文が並んで、なんだかなぁ、と思うことが多いです。
例えばjavaで次のような感じ。クラスAaa、Bbbなどは省略します。

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < args.length; i++) {
            create(args[i]);
        }
    }

    private static void create(String devName) {
        Map<String, Supplier<Xxx>> factory = new HashMap<>();
        factory.put("A", Aaa::new);
        factory.put("B", Bbb::new);
        Supplier<Xxx> sup = factory.get(devName);
        if (sup != null) { // ★
            Xxx xxx = sup.get();
            System.out.println(xxx.getProduct());
        }
    }
}

factory.get()のところをgetOrDefault()使ってnullが返らないようにする手もありますが、このケースでは本来エラーになるケースでsup.get()で無駄なインスタンスを生成してしまうのでいやだなぁと。
もう20世紀じゃない。javaでNullじゃなければ実行する、みたいなスマートな方法があるはず。どう調べればよいかわからないのでたどり着くのに時間がかかりましたが、こんな方法があるようです

    private static void create(String devName) {
        Map<String, Supplier<Xxx>> factory = new HashMap<>();
        factory.put("A", Aaa::new);
        factory.put("B", Bbb::new);
        Optional<Supplier<Xxx>> optxxx = Optional.ofNullable(factory.get(devName));
        optxxx.ifPresent(sup -> System.out.println(sup.get().getProduct())); // supにoptxxxが入る
    }

java.util.Optionalを使ってofNullableで「この変数、nullかもしれない」と申告しておいて、ifPresentで「もしnullじゃなかったらヨロシク」ってことらしい。
このコードではifPresentで実行までしていますが、生成したインスタンスを返して戻り先で実行させるならこんな感じ。「nullかもしれない」値をOptionalに入れて処理して、最後にorElseでインスタンスを取り出すみたい。

        Optional<Supplier<GenHtml>> maker = Optional.ofNullable(factory.get(htmlMode.toLowerCase(Locale.getDefault())));
        Optional<GenHtml> makerMethod = maker.map(zz -> zz.get());
        return makerMethod.orElse(null);

最初の方の例はこのページに書くためにでっち上げたコードだったけれど、こっちは自分のコードからコピペ。
多分読み慣れればifでnullチェックするよりも読みやすくなるのでしょうね。

問題というほどの問題ではないのですが、ifPresentやmapの中でラムダ式を使うのでjacocoではサイクロマチック数を一つ使ってしまうのですよね。Optionalの処理をメソッドにして追い出してしまうとかいう使い方を想定しているのでしょうかねぇ。

2024年03月10日 プログラミング雑談

匍匐前進

今年作っていたjavaのプログラム、VSCodeでMavenを使っていましたが、gradleも使ってみたくて。

VSCodeなのでGradle for Javaのプラグインを入れて、コマンドパレットで"Create a Gradle Java Project"でKotlinでJUnit5だったかな、そんな感じで選んでプロジェクトを作成。
もう一歩進むたびにやり方をググって・・・
依存パッケージの設定はbuild.gradle.ktsに

dependencies {
    // This dependency is used by the application.
    implementation("org.jsoup:jsoup:1.17.2")
    implementation("org.apache.logging.log4j:log4j-api:2.22.0")
    implementation("org.apache.logging.log4j:log4j-core:2.22.0")
}

とか書いて、VSCodeの左の象のアイコン→Tasks→build→buildしたらエラー。
どうやらbuild.gradleを更新したらUpdateする必要があるみたい。Mavenの時はpom.xmlを更新すると更新しますかみたいなメッセージボックスか何かが出てUpdateされていたみたいですが、まだ私の環境はbuild.gradleを更新しますかみたいなメッセージボックスか何かが出ているのですが反映されていないみたい。(追記)JDKとJREをインストールしなおしたら解決しました
とりあえずVSCodeを終了して立ち上げなおせば反映される。

Javaのソースファイルとテスト用データファイルを一式コピーしてbuild。今度はコンパイルが通ったけれど今度はテストでエラー。Webページのhtmlファイルを作るプログラムなので、生成したファイルの中の文字をチェックするのだけれど、UTF-8の文字列にもかかわらずShift-jisのつもりで比較している模様。UTF-8のソースファイルなのにShift-JISとしてコンパイルされているみたい。文字コードが誤認識されていてもビルドが通るとは恐るべし
VSCodeのエクステンションの設定かしらと思ってEncodeとか頑張って探すけれど設定する箇所が見つからない。
いろいろググってたらbuild.gradleで設定するらしい。このサイトの記載をそのまま使わせていただきました。

tasks.withType<JavaCompile>().configureEach {
    options.encoding = "UTF-8"
}

すっかり忘れていたけれど、Mavenの時はpom.xmlに

  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

みたいなのを書いた気がします。

VSCodeのjavaのプラグイン(?)でCreate Java Project→Maven→archetype-quickstart-jdk8とかで入ってくるcheckstyleとかjacocoとかはまだどうやったら使えるのかわからないし、log4jもまだlog4j2.xmlにパスが通っていないみたいでログが出てこないし、しばらくは前途多難な匍匐前進なのだな
でもググれば何かわかるというのは実に助かります。良い時代ですね。

2024年03月02日 プログラミング雑談

安いChromeBookも割り切って使えば悪くない

電子書籍リーダーのつもりで買ったChromeBookですが、シリンドリカルでは無いキーボードですが意外と打ちやすいので、こりゃ私のWebページ更新用の環境として使うのも悪くないかも? と思い始めています。
私はローマ字入力ではなくかなキー入力派で、普通のAndroidタブレットで適当なブルートゥースキーボードをつけてもかな入力が満足にできずに困っていたのですが、このChromeBookは普通にかな刻印ありのキーボードが付いてまして、普通にかなキーが使えています。Windowsで言うところのIMEは標準の英数字(日本語)キーボードだと思います。
WindowsではIMEのON/OFF切り替えはデフォルトではTABキーの上の日英キーですけれど、このトグル動作がいまいち不便なので変換キーでIME ON、英数キーでIME OFFに設定していました。ChormeBookでは英数キーの位置にメニューボタンらしいものがありますのでこれをIME OFFとして使うことはできないのですが、Windowsの無変換キーの位置にある英数キーでIME OFFできるのでこれはこれで便利。Windowsでも無変換キーでIME OFFにする設定で使い始めました。何年もWindows使っていますけれど、無変換キーって押したことなかったかも。

エディタはJota+。Aキーの横がChromeBookはメニューボタンですし、薄っぺらいキーボードですのでctrlキーが押しにくいのであれですが、Jota+ってctrl-hやctrl-mといった昔懐かしいショートカットが使えるんですよね。ダイヤモンドカーソル(って言ったっけ?)は使えないみたいですけど。これ書きながら、もしかしたらと思ってヘルプを見たらショートカットキーは自分で設定できる模様。ダイヤモンドカーソルしたければ設定できますね。もっとも職場でWindowsを使わなくてはならないのでダイヤモンドカーソルに体が慣れてしまうと仕事にならないかも。
ってことで、ここまでChromeBookで書いてみました。

2024年02月24日 ChromeBook CZ1000DV

Java AutoValueの私的なメモ

Effective Javaで今更ながらJavaを勉強中
最初の方の章でdataクラスを作るならequalとかちゃんとやらなきゃだめだよとか書いてあるみたい。自分で定義した値クラスを比較してないなら問題ないんでしょ? と思いながら、ちょっとお試し。
githubのAutoValue
detailed documentationをまるっとコピーしてしまうと、コード側の使い方はこんな感じらしい。@AutoValueというアノテーションを書くこととabstractクラスにすることがポイントらしい。インスタンス生成するためにabstractじゃないクラス名が必要だからcreateメソッドも必要ってことかな。

import com.google.auto.value.AutoValue;

@AutoValue
abstract class Animal {
  static Animal create(String name, int numberOfLegs) {
    return new AutoValue_Animal(name, numberOfLegs);
  }

  abstract String name();
  abstract int numberOfLegs();
}

mavenの場合pom.xmlには次のように書くみたい。${auto-value.version}は適切なバージョンに置き換える。

<dependencies>
  <dependency>
    <groupId>com.google.auto.value</groupId>
    <artifactId>auto-value-annotations</artifactId>
    <version>${auto-value.version}</version>
  </dependency>
</dependencies>

これだけだとAutoValue_Animalなんてクラス知らないって言われるので次の記載も必要みたい

<build>
  <plugins>
    <plugin>
      <artifactId>maven-compiler-plugin</artifactId>
      <configuration>
        <annotationProcessorPaths>
          <path>
            <groupId>com.google.auto.value</groupId>
            <artifactId>auto-value</artifactId>
            <version>${auto-value.version}</version>
          </path>
        </annotationProcessorPaths>
      </configuration>
    </plugin>
  </plugins>
</build>

これでビルドするとtarget/generated-sourcesの下にAutoValue_Aminal.javaが作られる。
私はたいしてjavaのコードを書いていないからこれまでこういうことを知らなくても実害はなかったけれど、コンテナに自作クラス(のインスタンス)を入れて何かさせる場合はequalとかちゃんと作らなきゃならないようなので、今は実害が無くてもちゃんと作る習慣を今からつけていかないと将来発見が難しいエラーを作りこんでしまうって事だろうな。

2024年02月24日 プログラミング雑談

サイクロマチック数 max 5の世界

久しぶりにプログラムを書くといろいろ勉強になりますね。
今回の一番の収穫はメソッドのサイクロマチック数をmax 5で作るのも良いものだ、という事を実感したことかもしれません。
最初はmavenの環境をチュートリアル見ながら構築したらデフォルトでそのような設定になっていたというだけなのですが、これがデフォルトという事は何か意味があるに違いないと思ってmax 5縛りで作ってみました。
最初に影響が出たのがswitch文。こんなの使うとあっという間にサイクロマチック数5を超えてしまいます。ファクトリーメソッドで処理を切り分けるようにしました。ファクトリーメソッドでもファクトリー部分で分岐が出ないようにArrayListとかに選択肢を詰め込んでおいてget(key)で探したりforeachで探したり。
次にif文の使用。メソッドの責務をシンプルにして、メソッドの上から下まで条件分岐なしでいかに流しきるか考えるようになりました。今回作っていたプログラムは、テキストファイルを読み込んでhtmlに変換して書き出すというシンプルなコマンドラインプログラムでした。メソッドの入り口で「入力ファイルを確認する」みたいなメソッドでチェックして、NGならエラーリターンし、その後の処理は余計なことは考えずに上から下まで一気に流す、みたいなスタイルになっていきました。

そのうちメソッドのサイクロマチック数 max 5はまあ普通に守れるようになってきましたが、次にクラスでmax 20という条件で引っかかるようになりました。メソッドが1つあればサイクロマチック数も最低1あるという数え方ですので、クラスのメンバー変数がいくつかあってsetter、getterを書き始めるとたちまち超えます。setter、getterは今回はあまり書かないで作ってみました。これが正しい対処法かどうかわかりませんが、
それよりも「もし入力ファイルが無かったら」はFileReaderクラスの責務、「もし入力ファイルの記載が間違っていたら」は処理するクラスの責務、みたいにクラスの責務を整理して、一つのクラスで処理しなければならないメソッドを減らすことに注力してました。
テキストファイルを読み込んだり、htmlをファイルに書き込んだりするのはhtmlを生成するクラスの責務ではないよね、ということで、ファイル読み書きは別クラスに切り出したり。

おかげで単体テストコードも書きやすいです。まだあまり書けていませんが、これまでコードの構造のせいでテストが書きにくいといった事には出くわしていません。
まだ単体テストを一通り書いていないのにこんなことを言うのもなんですが、単体テストってプログラマーの意図通りコードが書けているかどうかのテストなのだなぁと実感していました。単体テストが通っているのに出力されたhtmlファイルが意図通りではないことが頻発しています。これはplaywrightみたいなツールで結合テストするしかないのかもしれないですね

そうそう、サイクロマチック数とは関係ないかもですが、今回は(今回こそ)設計書をちゃんと書くぞと(まだ)思っています。DoxygenとかplantUMLとか使ってちまちま書いています。
私が飽きるのが先か、テストや設計書を作り切るのが先か、どうなるんでしょうね?

2024年02月04日 プログラミング雑談

ページのレイアウトをいじってました

ページの見た目をマイナーチェンジしました。
パソコンで見たときに、中途半端なウインドウ幅にしたときにレイアウトが崩れるのを放置していましたが、私のところではちゃんと表示するようにしたのと、スマホで見たときに少し見やすい感じを狙ってみました。
今回いじったのはcssファイルが中心で、ブラウザのキャッシュをクリアしないと変更が反映されないかも。
PC(firefox、chrome)とChromeBook(chrome)ではまあ想定通りの表示になったけれど、スマホのchromeでなぜか右に余白ができて右スクロールができてしまうのがちょっと気になる。あとはスマホのchromeで縦スクロールがカクカクする感じ。私の今のスマホ、5年位経ってたっけ・・・
(追記)スマホで右スクロールになってしまう件、ログ出力の英文がブラウザからは一単語に見えて改行できず、長い長い1行で表示していたためだったようです。cssファイルに

word-break: break-all;

って書いたら直りました。

2024年02月03日 このページのリフォーム

javaで正規表現

このページをテキスト形式からhtmlに変換するプログラムはC++で2009年に書いたものです。
これをjavaでjsoupを使って書き換えようと思い始めて多分2週間。
機能実現検証用の試作が動きました・・・。
もう若くないので夜更かしはできないし、平日昼間は仕事だし、このwebページをjava版の変換プログラムで作るのは2月に入ってからかなぁ。
秀丸の置換とかsedとかgawkで正規表現を便利に使っていますがjavaの場合のやり方を少しメモ。

Pattern pattern = Pattern.compile("^[ \t]*&([^:]+):") ;
Matcher matcher = pattern.matcher(inLine);
if(matcher.find()) {
    if(matcher.group(1).equals("end")) {

とかすると、"&end:"が検出できる模様。Patternの行からfindの行までは1行で書けるので、それなりにすっきり書くこともできるのですね。
はまったポイントは数字とマッチする"\d"は"\"自身がエスケープ文字なので"\\d"と書かねばならないとか、find()まで実行しないとgroupが使えないところですかね。

2024年01月21日 プログラミング雑談 このページのリフォーム

VSCodeでmavenでJUnitとかjacocoとか

割と最近までVisualStudioでC++の人だったのでjavaとかVSCodeとか、何かしようとするたびに壁にぶつかる今日この頃。
ググりまくりなのだけれど、右も左もわからない初心者なのでググるキーワードが多分不適切なのでしょう。全然情報が見つかりません・・・(涙)
VSCodeでExtension Pack for JavaとかMaven for Javaを入れて、簡単なコードを書いて、JUnitのテストコードを書いて実行してみてます。
コマンドパレットで"Maven Execute Commands..."で"install"を実行すると多分実行jarを作ってくれて、JUnitのテストを実行してくれて、カバレッジまで測ってくれるようです。ステキ。
そしたら間もなく
[WARNING] Rule violated for method com.segu.Index.addText(org.jsoup.nodes.Element, java.lang.String): complexity total count is 7, but expected maximum is 5
とか言われ始めました。
悪かったね! どうせ私のコードはスパゲッティだよ! とか思いながら、とりあえずcomplexityのmaximumを8とかにすれば良いんでしょ?ってことで、VSCodeのsettings.jsonとかに何か書けばいいんだろうなと思いながらググること何時間?。結局解決策がわからず、
[ERROR] Failed to execute goal org.jacoco:jacoco-maven-plugin:0.8.4:check
で"install"がエラーになってから手動でJUnitのテストを実行してました。
pom.xmlを見ると

<maximum>${jacoco.unit-tests.limit.method-complexity}</maximum>

という行があったので、method-complexityというパラメタ名でググったけれどわからず。
あきらめてcomlexityのチェック行をpom.xmlから全削除するという暴挙に出てERRORを回避して何日か過ごしました。
で、
別件でpom.xmlを見てたら

<jacoco.unit-tests.limit.method-complexity>5</jacoco.unit-tests.limit.method-complexity>

なんて行があるではないですか。なんだ、pom.xmlの中で上限値を設定してたのかよ!ってことで、ここで上限値を8とかにしたらWARNINGもERRORも消えてすっきり

で、さらに私の前に(多分客観的には低い)壁が出現するわけですよ
JUnitのテストはlog4jで何のテストを実行したかログを出力したいので、log4j2.xmlが見えるようにクラスパスを設定したいのだけれど、どうやったら設定できるかわからずに半日ググった結果、このサイトを見つけました。
いや、見つけたってなんだよ。VSCodeのMavenプラグインが設定してくれたpom.xmlにmaven-surefire-pluginって書いてあんだから、surefireのオフィシャル見に行くのは当然だろ!って気もしますが、わかんないことばかりでどこを見に行って何を読めばいいかわかんないんですよ....と言い訳しておきます。
私はプロジェクトのルートにlog4j2.xmlを置いているのでpom.xmlに次のように書けばよいみたいです。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>${maven-surefire-plugin.version}</version>
  <configuration>
    <additionalClasspathElements>
      <additionalClasspathElement>./</additionalClasspathElement>
    </additionalClasspathElements>
  </configuration>
</plugin>

数日経つと忘れちゃうんだろうなという事で記録を残してみます。備忘録かよっ

2024年01月20日 プログラミング雑談

Jsoupの使い方がよくわかんない

このWebページを生成するプログラムをC++11以前の古いC++で作っていたのをjavaでjsoupを使って書き換えようという気分になって書き換え始めたのだけれど、jsoup自体初心者なので細かい問題にぶつかってばかり。
最初はjsoupでnodeとかdocumentとかelementとかの使い分けがわからないところからスタートしているのでjavadocっぽいドキュメントを頑張って読んでいました。
その後はxmlヘッダーやドキュメントヘッダーの付け方に悩み、今は改行の付け方に悩んでいます。
一応このページはXHTML 1.0 Strictで作っているので、改行は<br />なのですが、appendElement("br /")だと閉じタグが生成されて<br /></br />になってしまうんですよね。
appendElement("br")ならばならば閉じタグが作られず<br>だけが生成されるのに。
もしかしてjsoupでこれはxhtmlだとかhtml5だとか教えることができて、その辺の設定ができるとうまいことやってくれるのかしら?
(追記)やっとわかった。XHTMLだから、jsoupをhtmlモードではなくxmlモードで動かさなければならない模様。

doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);

してからdoc.outerHtml();すれば良いんだ!
とりあえずXHTMLの骨組みはこんな感じで生成できそう

doc = new Document("");
XmlDeclaration xmlDecl = new XmlDeclaration("xml", false);
 
xmlDecl.attr("version", "1.0");
xmlDecl.attr("encoding", doc.charset().displayName());
DocumentType docType = new DocumentType("html", 
"-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
 
doc.appendChild(xmlDecl);
doc.appendChild(docType);
 
Element html = doc.appendElement("html");
html.attr("xmlns","http://www.w3.org/1999/xhtml");
html.attr("xml:lang","ja");
html.attr("lang","ja");
Element head = html.appendElement("head");
head.append("<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\" />");
head.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");
head.append("<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />");
doc.title("MyPage");
Element body = html.appendElement("body");
 
Element ddd = body.appendElement("div");
ddd.appendChild(new Comment("Comment Node"));
ddd.appendChild(new TextNode("TextNode"));
ddd.appendElement("br");
ddd.appendText("&");
 
doc.outputSettings().indentAmount(0);
doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);
 
doc.outerHtml();

誰かのお役に立てれば。

2024年01月13日 プログラミング雑談 このページのリフォーム

短波ラジオPL-330メモ

マニュアルを見ないとわかりにくい使い方をメモ

スリープタイマー設定

電源OFF状態でPOWER長押し → チューニングダイヤルでタイマー時間設定
次から電源ONでスリープタイマーになる
スリープタイマーをOFFにするには再び電源OFF状態でPOWER長押ししてタイマー時間をOFFに設定する。

自動電源ON設定(アラーム)

電源OFF状態でALARM長押し → チューニングダイヤル(時)と音量ダイヤル(分)でON時刻設定 → ALRAM → チューニングダイヤルでONし続ける時間(分)を設定 → ALRAM

自動電源ON状態から操作可能な状態にする

POWER を押す = 操作を受け付けるようになる

自動電源ON状態(アラーム)を一時的に止めてスヌーズ

DISPLAYを押す = 自動電源ONを一時的に止めて、5分後に再び自動電源ON

自動電源ON時の放送局設定

聞きたい放送局に合わせ、"M" → ALARM → Enter(リターン);

中波放送のアンテナ切り替え(マニュアル非掲載)

中波放送受信中に "3"ボタン長押し → CH-S と表示される。バンド表示が"SW"も表示される。
この状態で、アンテナが内蔵バーアンテナから短波・FM用のロッドアンテナ(またはアンテナ端子に接続された外部アンテナ)に切り替わっている。受信周波数を変更するなど、何か操作すると表示は変わらないけれどアンテナが内蔵バーアンテナに戻ってしまう模様
再び "3"ボタン長押し → CH-A と表示され、バンド表示の"SW"も消える。アンテナが内蔵バーアンテナに戻る。

SSB受信時の周波数のキャリブレーション(マニュアル非掲載)

SSB受信中 チューニングステップを10Hzにしてゼロビートを取って "LSB"長押し するとその周波数がKHz単位に丸められる。(上手に表現できなくて申し訳ない)

ファームウェアバージョン表示(マニュアル非掲載)

電源OFF時にVF/VM長押し
ディスプレイがすべて表示され、次に右上に3306等と表示される。おそらく上2桁が機種を表し、下2桁がファームバージョン。
ファームバージョン 3305 は、SSB受信時に10Hzステップでチューニングしていてもチューニングダイヤルを早めに回すと50Hzに自動で切り替わる模様。
ファームバージョン 3306 は、チューニングステップが自動で切り替わらなくなっている模様。

2022年04月23日 短波ラジオ PL-330

Valid XHTML 1.0!Valid CSS!