このトピックでは、ABAPでUniCodeのシステムからSJISコードで固定長ファイル出力の方法を取り上げて説明します。
背景
ABAPで文字コードの関係でSJISコードで固定長ファイルを出力するには少し工夫する必要があります。 タブ区切りやカンマ区切りのファイル出力にするほうがだんぜん楽ですが、ふるい既存システムへの連携で固定長ファイルにしなければならない場面がしばしばあります。
固定長項目出力
固定長ファイル出力の基本は、項目を固定バイト長に出力させることです。
問題点
以下の構造体をファイルに出力することを例とします。
TYPES: BEGIN OF typ_row, col1 TYPE C LENGTH 10, col2 TYPE C LENGTH 12, END OF typ_row.
Unicodeシステムのため、co1に定義されたLENGTH=10はバイト数ではなく文字数ですので、SJISで出力されるバイト数は可変になります。 一番少ないのは、すべて半角文字の場合であり、出力バイト数が10×1半角文字1バイト=10バイトになります。 一番多いのは、すべて全角文字の場合であり、出力バイト数が10×1全角文字2バイト=20バイトになります。 col1の固定長出力は以下の2パターンに分けることができます。
- 固定長>=20バイト
col1の実際の出力バイト数が20を超えることがないため、カットする処理は必要がありません。
但し、場合によって後ろにスペースを埋める必要があるため、col1の実際の出力バイト数を計算しなければなりません。 - 固定長<20バイト、例えば:10バイト
col1の実際の出力バイト数を計算して、10バイトに未満の場合のスペース埋め処理を実装するほか、10バイトを超えた場合の既存文字列のカット処理も実装しなければなりません。カットする際に、カットが全角文字の真ん中にならないように注意する必要があります。
対応方法
上記の課題を対応するポイントは以下になります。
- 出力バイト数計算処理
メソッドcl_abap_list_utilities⇒dynamic_output_lengthを利用して、出力バイト数を計算します。
このメソッドは各文字が全角文字か半角文字かを判断して、全角文字なら2、半角文字なら1というアルゴリズムで出力長を計算しています。 - 文字列カット処理
メソッドcl_abap_list_utilities⇒read_from_display_layoutを利用して、文字列のカット処理を行います。
このメソッドはカットされる箇所に全角文字が跨っている場合、文字化けにならないように該当全角文字を丸ごと捨てるようにしております。 - スペース埋め処理 \\ CONCATENATE命令は文字列を連結する際に、デフォルトで文字列の後ろのスペースを削除するため、スペース埋め処理を行う時は、RESPECTING BLANKSオプションをつける必要があります。
サンプルコード
固定バイト数で文字列を出力するサブルーチンのサンプルコードです。
*&---------------------------------------------------------------------* *& Form F_OUTPUT_FIXED_BYTES *&---------------------------------------------------------------------* * 固定バイト数で文字列出力 *----------------------------------------------------------------------* * -->U_LEN : 出力バイト長 * -->U_FIELD : 入力値 * -->C_STR : 出力文字列 *----------------------------------------------------------------------* FORM f_output_fixed_bytes USING u_len TYPE i u_field CHANGING c_str.DATA:
l_len TYPE i, "length
l_cnt TYPE i,
l_rc TYPE abap_list_repl_rc.
CLEAR: c_str,
l_cnt.
- byte数取得
CALL METHOD cl_abap_list_utilities=>dynamic_output_length
EXPORTING
field = u_field
RECEIVING
len = l_cnt. - データ長が出力バイト長を超えた場合、出力バイト長で文字列をカット
IF l_cnt > u_len.
TRY.
CALL METHOD cl_abap_list_utilities=>read_from_display_layout
EXPORTING
display_data = u_field
display_offset = 0
display_length = u_len
IMPORTING
field = c_str
rc = l_rc.
CATCH cx_parameter_invalid_range .
ENDTRY. - byte数再取得 (カット箇所に全角文字が跨っているケースを考慮)
CALL METHOD cl_abap_list_utilities=>dynamic_output_length
EXPORTING
field = c_str
RECEIVING
len = l_cnt. - バイト数が足りない場合は、後ろにスペースを埋める
WHILE l_cnt < u_len.
CONCATENATE c_str
' '
INTO c_str
RESPECTING BLANKS.
l_cnt = l_cnt + 1.
ENDWHILE.
ENDIF.
ENDFORM.