Java 「濁音」「半濁音」などなど、半角カナの扱いがかなり厄介でござる...

片仮名(かたかな)とは、日本語の表記に用いられる音節文字のこと。仮名の一種で、借字を起源として成立した。

片仮名 - Wikipedia

昭和、平成、と経て~、令和になったしね、和の心!はい、日本に和の心が戻ったのか?どうもボクです。

というわけで、「半角カナ」の厄介なこと、厄介なこと、では、レッツトライ~。

 

半角カナとは

Wikipediaさん~!

半角カナ(はんかくカナ)、半角片仮名(はんかくかたかな, Halfwidth Katakana)とは、が半分(半角)の片仮名文字の事。

半角カナ - Wikipedia

Unicode では、全角片仮名(Fullwidth Katakana)と半角片仮名(Halfwidth Katakana)が異なる文字として登録されている。類似物として、Unicode には半角ハングル(Halfwidth Hangul)も登録されている。これらの半角文字は、Halfwidth and Fullwidth Forms(U+FF00-FFEF)に入っている。

半角カナ - Wikipedia

JIS X 0208では、片仮名を含む他の文字集合と同時に運用される場合におけるJIS X 0201片仮名文字集合の通称である。漢字を含む文字集合で定義された片仮名に対して、半分の文字幅で表示されることが一般的であったためこのように呼ばれる。

半角カナ - Wikipedia

JIS X 0201で規定される8ビット符号化およびShift_JISにおいて0xA1-0xDFの範囲の1バイト文字がこれにあたる。また、Shift_JISEUC-JPなどの符号化方式やUnicodeでも互換性の目的でこの文字集合をもっている。

半角カナ - Wikipedia

JIS X 0208:1997 『附属書 1(規定)シフト符号化表現』では、「参考 JIS X 0201 の片仮名用図形文字集合の割当ては、この規格の将来の改正では削除することを予定する。」と記載されている。

半角カナ - Wikipedia

JIS X 0213:2000 『附属書5(規定)文字の代替名称』では HALFWIDTH KATAKANA が記載されているが、「この附属書は、これまでの慣用的な利用との互換を目的としてだけ用いる文字の代替名称を規定する。」と書かれ、削除予定とは書かれていない。

半角カナ - Wikipedia

また、Microsoft WindowsMS-IMEにおいて日本語入力モードで未確定状態でF7を押すと全角カタカナ(ぜんかくかたかな→ゼンカクカタカナ)、F8を押すと半角カタカナ(はんかくかたかな→ハンカクカタカナ)となる。

半角カナ - Wikipedia

んで、

f:id:ts0818:20190723233615p:plain

"・「」、。ー"の6記号の半角版も半角カナの領域となっている。(0xA1-0xA5,0xB0)

半角カナ - Wikipedia

と。

つまり、 『゙』『゚』のような濁音や半濁音の他にも、

 は、1文字として扱われると。なので、全角『ガ』は1文字だけど、半角『ガ』だと、『カ』+『゙』の2文字として扱われるという(涙)。

 

何が問題だったのか

あるサイズまで、文字列を0埋めして、その文字列のbyte配列を設定する必要があったんだけど、「半角カナ」の『濁音』『半濁音』が影響して文字数が変わってくるので上手くいかないと。

ちなみに、

package main;

public class TestKana {

  public static void main(String[] args) {
    // TODO 自動生成されたメソッド・スタブ
    int strByteSize = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわゐゑをん".getBytes().length;
    int strLenSize ="あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわゐゑをん".length();

    String zenkakuKana = "レイワ、チョベリバ~!ピーパッパラッポ";
    String hankakuKana = "レイワ、チョベリバ~!ピーパッパラッポ";
    
    boolean isByte = true;
    System.out.println("バイト数: " + strByteSize);
    System.out.println(zenkakuKana.getBytes().length);
    System.out.println(hankakuKana.getBytes().length);
    System.out.println(lpadding(zenkakuKana, strByteSize, isByte));
    System.out.println(lpadding(hankakuKana, strByteSize, isByte));
    System.out.println(lpadding(zenkakuKana, strByteSize, isByte).length());
    System.out.println(lpadding(hankakuKana, strByteSize, isByte).length());
    System.out.println(lpadding(zenkakuKana, strByteSize, isByte).getBytes().length);
    System.out.println(lpadding(hankakuKana, strByteSize, isByte).getBytes().length);

    isByte = false;
    System.out.println("文字数: " + strLenSize);
    System.out.println(zenkakuKana.length());
    System.out.println(hankakuKana.length());
    System.out.println(lpadding(zenkakuKana, strLenSize, isByte));
    System.out.println(lpadding(hankakuKana, strLenSize, isByte));
    System.out.println(lpadding(zenkakuKana, strLenSize, isByte).length());
    System.out.println(lpadding(hankakuKana, strLenSize, isByte).length());
    System.out.println(lpadding(zenkakuKana, strLenSize, isByte).getBytes().length);
    System.out.println(lpadding(hankakuKana, strLenSize, isByte).getBytes().length);

  }
  
  public static String lpadding(String target, int size, boolean flg) {
//    return String.format(("%"+ (size - target.getBytes().length) + "s"), target);
//    return String.format(("%"+ (size - target.length()) + "s"), target);

    if (flg) {
      return String.format(("%"+ (size - target.getBytes().length) + "s"), target);

    } else {
      return String.format(("%"+ (size - target.length()) + "s"), target);

    }
  }
}

「バイト数」「文字数」どっちのパターンも試してみたけど、駄目そうね...

f:id:ts0818:20190724204449p:plain

⇧ 0埋めじゃなくて、スペース埋めだけど...

「全角カナ」「半角カナ」でバイト数とか噛み合わない(涙)。

 

Java で半角カナ、全角カナとか文字数を意識しない、つまりバイト数で

ということで、

stealthinu.hatenadiary.jp

⇧  先人の知恵を拝借。

OracleSQLでも、正規表現っぽいことができるらしい。

hensa40.cutegirl.jp

 

結論としては、マトリックスを作っとくみたい。

pgcafe.moo.jp

 

だけど、はじめからbyteで考えていける環境であれば、バイト数で計算すれば良いみたい?です。 「全角カナ」「半角カナ」を意識する必要はないかと...たぶん。

それに、「全角カナ」「半角カナ」が混合した文字列とかも考え出すと、はじめからbyteで考えたほうが良さ気?ですかね。

 

package main;

public class TestKana {

  public static void main(String[] args) {
    // TODO 自動生成されたメソッド・スタブ
    int strByteSize = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわゐゑをん".getBytes().length;
    int strLenSize = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわゐゑをん".length();

    String zenkakuKana = "レイワ、チョベリバ~!ピーパッパラッポ、アイムスキャットマ~ン!ガビーン";
    String hankakuKana = "レイワ、チョベリバ~!ピーパッパラッポ、アイムスキャットマ~ン!ガビーン";

    //    boolean isByte = true;
    //    System.out.println("バイト数: " + strByteSize);
    //    System.out.println(zenkakuKana.getBytes().length);
    //    System.out.println(hankakuKana.getBytes().length);
    //    System.out.println(lpadding(zenkakuKana, strByteSize, isByte));
    //    System.out.println(lpadding(hankakuKana, strByteSize, isByte));
    //    System.out.println(lpadding(zenkakuKana, strByteSize, isByte).length());
    //    System.out.println(lpadding(hankakuKana, strByteSize, isByte).length());
    //    System.out.println(lpadding(zenkakuKana, strByteSize, isByte).getBytes().length);
    //    System.out.println(lpadding(hankakuKana, strByteSize, isByte).getBytes().length);
    //
    //    isByte = false;
    //    System.out.println("文字数: " + strLenSize);
    //    System.out.println(zenkakuKana.length());
    //    System.out.println(hankakuKana.length());
    //    System.out.println(lpadding(zenkakuKana, strLenSize, isByte));
    //    System.out.println(lpadding(hankakuKana, strLenSize, isByte));
    //    System.out.println(lpadding(zenkakuKana, strLenSize, isByte).length());
    //    System.out.println(lpadding(hankakuKana, strLenSize, isByte).length());
    //    System.out.println(lpadding(zenkakuKana, strLenSize, isByte).getBytes().length);
    //    System.out.println(lpadding(hankakuKana, strLenSize, isByte).getBytes().length);

    // 一旦、「半角カナ」を「全角カナ」に変換
    String tmpHankakuKana = HanToZenForKKana(hankakuKana);
    int diffByte = Math.abs(tmpHankakuKana.length() - hankakuKana.length());
    System.out.println(diffByte);
    System.out.println("全角: " + tmpHankakuKana.length());
    System.out.println("半角: " + hankakuKana.length());
    System.out.println("全角: " + tmpHankakuKana);
    System.out.println("半角: " + hankakuKana);
    System.out.println("全角: " + tmpHankakuKana.getBytes().length);
    System.out.println("半角: " + hankakuKana.getBytes().length);
    System.out.println(padding(tmpHankakuKana, strByteSize));
    System.out.println(padding(hankakuKana, strByteSize));

    System.out.println(padding(tmpHankakuKana, strByteSize).getBytes().length);
    System.out.println(padding(hankakuKana, strByteSize).getBytes().length);

    System.out.println("000000000000000000000".getBytes().length);
    System.out.println("000000000".getBytes().length);
  }

  public static String padding(String target, int size) {
    int end = target.getBytes().length;
    for (int i = 0; i < size - end; i++) {
      target = "0" + target;
    }
    return target;
  }

  public static String lpadding(String target, int size, boolean flg) {
    //    return String.format(("%"+ (size - target.getBytes().length) + "s"), target);
    //    return String.format(("%"+ (size - target.length()) + "s"), target);

    if (flg) {
      return String.format(("%" + (size - target.getBytes().length) + "s"), target);

    } else {
      return String.format(("%" + (size - target.length()) + "s"), target);

    }

  }

  private static final String kanaHanZenTbl[][] = {
      // 2文字構成の濁点付き半角カナ
      // 必ずテーブルに先頭に置いてサーチ順を優先すること
      { "ガ", "ガ" }, { "ギ", "ギ" }, { "グ", "グ" }, { "ゲ", "ゲ" }, { "ゴ", "ゴ" },
      { "ザ", "ザ" }, { "ジ", "ジ" }, { "ズ", "ズ" }, { "ゼ", "ゼ" }, { "ゾ", "ゾ" },
      { "ダ", "ダ" }, { "ヂ", "ヂ" }, { "ヅ", "ヅ" }, { "デ", "デ" }, { "ド", "ド" },
      { "バ", "バ" }, { "ビ", "ビ" }, { "ブ", "ブ" }, { "ベ", "ベ" }, { "ボ", "ボ" },
      { "パ", "パ" }, { "ピ", "ピ" }, { "プ", "プ" }, { "ペ", "ペ" }, { "ポ", "ポ" },
      { "ヴ", "ヴ" },
      // 1文字構成の半角カナ
      { "ア", "ア" }, { "イ", "イ" }, { "ウ", "ウ" }, { "エ", "エ" }, { "オ", "オ" },
      { "カ", "カ" }, { "キ", "キ" }, { "ク", "ク" }, { "ケ", "ケ" }, { "コ", "コ" },
      { "サ", "サ" }, { "シ", "シ" }, { "ス", "ス" }, { "セ", "セ" }, { "ソ", "ソ" },
      { "タ", "タ" }, { "チ", "チ" }, { "ツ", "ツ" }, { "テ", "テ" }, { "ト", "ト" },
      { "ナ", "ナ" }, { "ニ", "ニ" }, { "ヌ", "ヌ" }, { "ネ", "ネ" }, { "ノ", "ノ" },
      { "ハ", "ハ" }, { "ヒ", "ヒ" }, { "フ", "フ" }, { "ヘ", "ヘ" }, { "ホ", "ホ" },
      { "マ", "マ" }, { "ミ", "ミ" }, { "ム", "ム" }, { "メ", "メ" }, { "モ", "モ" },
      { "ヤ", "ヤ" }, { "ユ", "ユ" }, { "ヨ", "ヨ" },
      { "ラ", "ラ" }, { "リ", "リ" }, { "ル", "ル" }, { "レ", "レ" }, { "ロ", "ロ" },
      { "ワ", "ワ" }, { "ヲ", "ヲ" }, { "ン", "ン" },
      { "ァ", "ァ" }, { "ィ", "ィ" }, { "ゥ", "ゥ" }, { "ェ", "ェ" }, { "ォ", "ォ" },
      { "ャ", "ャ" }, { "ュ", "ュ" }, { "ョ", "ョ" }, { "ッ", "ッ" },
      { "。", "。" }, { "「", "「" }, { "」", "」" }, { "、", "、" }, { "・", "・" },
      { "ー", "ー" }, { "", "" }
  };

  public static String HanToZenForKKana(String p) {
    StringBuffer sb = new StringBuffer();

    for (int i = 0, j = 0; i < p.length(); i++) {
      Character c = new Character(p.charAt(i));
      // Unicode半角カタカナのコード範囲か?            
      if (c.compareTo(new Character((char) 0xff61)) >= 0
          && c.compareTo(new Character((char) 0xff9f)) <= 0) {
        // 半角全角変換テーブルを検索する
        for (j = 0; j < kanaHanZenTbl.length; j++) {
          if (p.substring(i).startsWith(kanaHanZenTbl[j][0])) {
            sb.append(kanaHanZenTbl[j][1]);
            i += kanaHanZenTbl[j][0].length() - 1;
            break;
          }
        }

        // 検索できなければ、変換しない
        if (j >= kanaHanZenTbl.length) {
          sb.append(c);
        }
      } else { // Unicode半角カタカナ以外なら変換しない
        sb.append(c);
      }
    }
    return sb.toString();
  }

}

結果

f:id:ts0818:20190724233722p:plain

日本語って本当にプログラミングでは困った存在ですかね...

「文字数」でいくか、「バイト数」でいくか、それが問題だ、ですかね...

 

今回はこのへんで。