努力したWiki

推敲の足りないメモ書き多数

ユーザ用ツール

サイト用ツール


documents:etl:pentaho:pentaho-015

108.ゾーン形式を扱ってみる

2026-05-28
値にゾーン形式が来る場合があるのでその扱い方の1例。

固定幅の数値データ

固定長のファイルでもカンマ区切りでも良いのですけど、稀に固定幅の数値情報を処理する必要があったりします。

「稀」なはずなのだけど、処理する必要が出てしまったので対応してみましょう。このデータは文字コードがSJISで、改行なしの固定幅52文字レコードになっているデータです。これをUTF-8のCSVに変更します。

文字コードはSJIS(ASCII)
 
 1~ 8 桁:YYYYMMDD形式の日付
 9~12 桁:4桁の番号
13~22 桁:10桁のコード
23~27 桁:5桁(整数部4桁、小数点以下1桁)の単価
28~32 桁:5桁の数量
33~52 桁:コメントテキスト

Pentahoには固定幅ファイルの読み込みステップがあるのでそれを利用します。

無事に変換が出来ました。

項目の定義を行っています。この指定に従って項目が切り出されます。

テキスト部分に適当な加工を加えています。これは本来不要な処理なのですが、おそらくPentahoの不具合で、ファイル出力で文字コードが化けてしまいます。 推測ですが、読み込んだだけではPentaho内部で正しく文字コードを認識できないのかもしれません。影響のない文字項目の操作を行って無理やり認識をさせます。



UTF-8を指定してCSVを吐き出すだけです。必要なら書式を指定しておきます。

ゾーン形式の数値データ

ゾーン形式という数値データ形式があります。いにしえのメインフレームの時代からあるモノで、COBOLやFORTRANで作成するデータがそうなってたりします。
例えば COBOL で U-PRICE PIC S9(5)V1. や QTY PIC S9(5). のような項目に適用されるデータ形式です。

数値が正の数値なら固定幅の数値を扱うのと同じやり方で構いません。ですが負の数値の時に事情が変わります。 数値の最終桁の文字に、符号情報が付与されて数字の文字ではなくなってしまうんです。002.ゾーン形式、パック形式を参照してください。

このようなデータを読み込む事になったとします。

QTYの項目の値として 0002} が格納されています。これはゾーン形式で -20 を表しています。 “}“が符号情報のマイナスを持っている”0”の意となります。 1なら“J”、 9なら“R”です。

つまりこのゾーン形式を扱うには、最終桁の文字が符号を含んだ意味合いの文字かどうかの判断をして適切な処理を行う必要がある訳です。
で。これをPentahoの機能だけで対応しようとするととんでもなく面倒になります。

早速 QTY の対応をしてみます。

最初の定義から一気に増えました。

QTYを文字項目として読み出します。

QTYを先頭4文字とお尻の1文字に分割しています。この始点・終点の指定は Java の String.substring() の仕様に合わせてあるようです。

項目SIGNED-CHARで示す最終桁の文字と、これに対応する項目VALの数字文字、項目SIGNの正負符号を表す値で構成しています。これをストリーム参照でぶつけて適切な組み合わせを得ます。 “}“~”R”以外に“p”~“y”があるのは、後者の形式もゾーン形式として存在するからです。

"}"~"R":F,N,H,I 社で使われている形式
"p"~"y":OracleやGnuCOBOLで使われる形式。※ここではVAXスタイルのゾーン形式と呼称

つまりどちらの形式でも対応できるようにしてみた、という事です。

項目QTY-REARと項目SIGNED-CHARが一致するデータグリッドの 項目VALと項目SIGNを取得します。

項目QTY-AFTERに項目QTY-FRONTと項目VALの結合結果を格納します。つまり符号情報を取り除いた数字文字列に編集します。

項目QTY-AFTERをString型からInteger型に変換しています。

項目QTY-AFTERと項目SIGNを乗算して結果を項目QTY-CALCEDへ格納します。これで、ゾーン形式を符号を加味した数値へ変換する事が出来た事になります。


項目QTY-CALCEDを項目QTYへリネームしてからCSVファイルへ出力します。

結果はこうなりました。

ひとつの項目でこれだけ大変です。複数あったらとてもではありませんがこれで対処するのは困難だと思います。

Javaの力にすがる方が良い

Pentahoのバグを踏みかけたりしましたが、Javaで対応できそうなので方法を公開します。 と言いますか、こちらの手法をお勧めします。

import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;
import java.math.BigDecimal;
 
Map<String, String[]> zoneMap = new HashMap<String, String[]>(){{
        put("0", new String[]{"0",""});
        put("1", new String[]{"1",""});
        put("2", new String[]{"2",""});
        put("3", new String[]{"3",""});
        put("4", new String[]{"4",""});
        put("5", new String[]{"5",""});
        put("6", new String[]{"6",""});
        put("7", new String[]{"7",""});
        put("8", new String[]{"8",""});
        put("9", new String[]{"9",""});
        put("}", new String[]{"0","-"});
        put("J", new String[]{"1","-"});
        put("K", new String[]{"2","-"});
        put("L", new String[]{"3","-"});
        put("M", new String[]{"4","-"});
        put("N", new String[]{"5","-"});
        put("O", new String[]{"6","-"});
        put("P", new String[]{"7","-"});
        put("Q", new String[]{"8","-"});
        put("R", new String[]{"9","-"});
        put("p", new String[]{"0","-"});
        put("q", new String[]{"1","-"});
        put("r", new String[]{"2","-"});
        put("s", new String[]{"3","-"});
        put("t", new String[]{"4","-"});
        put("u", new String[]{"5","-"});
        put("v", new String[]{"6","-"});
        put("w", new String[]{"7","-"});
        put("x", new String[]{"8","-"});
        put("y", new String[]{"9","-"});
    }};
 
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException {
  if (first) {
    first = false;
  }
 
  Object[] r = getRow();
 
  if (r == null) {
    setOutputDone();
    return false;
  }
 
  r = createOutputRow(r, data.outputRowMeta.size());
 
  String    QTY       = get(Fields.In, "QTY").getString(r);
  String[]   QTY_item  = (String[]) zoneMap.get(QTY.substring(QTY.length() - 1));
  BigDecimal QTY_after = new BigDecimal(String.format("%s%s%s",QTY_item[1], QTY.substring(0, (QTY.length() - 1)), QTY_item[0]));
 
  get(Fields.Out, "QTY-AFTER").setValue(r, QTY_after);
 
 
  // Send the row on to the next step.
  putRow(data.outputRowMeta, r);
 
  return true;
}

先のPentahoの定義内にあった

  • 文字列カット
  • データグリッド
  • ストリーム参照
  • 計算
  • 選択/名前変更1
  • 計算2

でやっていた事をこの Javaのコードで一気に処理しています。

これなら、必要な項目の処理を増やすのが容易になったはずです。
この例では項目QTYをJavaのBigDecimal型に変換して、PentahoのBigNumber型の項目QTY-AFTERへ書き出しています。

Integer型でも行けそうですが、Pentahoがエラーを吐き出して駄目でした。数値関係はBigNumberで対処するのが無難そうです。



GUI側では 項目QTYに小数点以下1桁が表示されていますが、出力されたファイルには入っていないのでご安心ください。
出力する際に項目へ書式を適用して小数点以下の出力を抑止しています。

パック形式は?

パック形式はパック形式で別のやり方を考えなきゃいけないけど、まぁ、必要になったらやります。

documents/etl/pentaho/pentaho-015.txt · 最終更新: by k896951

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki