[Talend]ファイル内のEOFを取り除く

2015.12.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

不要な制御文字コードを取り除く

データ分析系の案件をやっているといろんな種類のCSVもしくはTSVファイルと連携することがあります。
よくあるケースとして

  • 文字コードがSHIFT−JISで連携されてくるケース
  • 文字コードがEUCで連携されてくるケース
  • 改行コードがCRLFで連携されてくるケース
  • 改行コードがCRで連携されてくるケース
  • 改行コードがLFで連携されてくるケース
  • 項目がスペース埋められて連携されてくるケース

等々

Amazon Redshiftへデータロードする際は文字コードをUTF-8にすることが必須条件となるので、文字コードの変換はよく行います。

ただし、上記のパターンについてはコンポーネント側のオプション等で吸収できるので、連携フォーマットの仕様さえ分かれば問題ないですが、中には制御文字コード等が入ってくるケースもあります。
今回はその制御文字コードのEOF(ファイル終端コード)を取り除くジョブを作ってみました。
利用頻度は少ないかもしれませんが、作ったので備忘録として。

使用したサンプルCSVは
・文字コードはUTF−8
・改行コードはLF

Sublime Textで開いた場合にEOFがSUBと表示されています。
CM_BLOG7_1

odコマンドで一応コードとキャラクタ表示をさせたものが以下で、一番最後に1aのコードが入っています。これがEOFのコードとなります。

$ od -cx eof_sample.csv
0000000    "   s   a   m   p   l   e   1   "   ,   0   ,   "   0   1   "
             7322    6d61    6c70    3165    2c22    2c30    3022    2231
0000020    ,   "   A   A   "   ,   "   1   "   ,   "   2   0   1   5   1
             222c    4141    2c22    3122    2c22    3222    3130    3135
0000040    1   2   0   "   ,   "   9   8   7   6   5   4   "   ,   "   3
             3231    2230    222c    3839    3637    3435    2c22    3322
0000060    2   "   ,   "   1   0   "   ,   "   1   2   "   ,   "   3   4
             2232    222c    3031    2c22    3122    2232    222c    3433
0000100    5   6   7   8   "   ,   "   0   0   1   "   ,   "  サ  **  **
             3635    3837    2c22    3022    3130    2c22    e322    b582
0000120   ン  **  **  プ  **  **  ル  **  **  1  **  **                
             83e3    e3b3    9783    83e3    efab    91bc    2020    2020
0000140        "   ,   "   2   0   1   5   1   2   0   9   "  \n   "   s
             2220    222c    3032    3531    3231    3930    0a22    7322
0000160    a   m   p   l   e   2   "   ,   0   ,   "   0   1   "   ,   "
             6d61    6c70    3265    2c22    2c30    3022    2231    222c
0000200    B   B   "   ,   "   1   "   ,   "   2   0   1   5   1   2   0
             4242    2c22    3122    2c22    3222    3130    3135    3032
0000220    2   "   ,   "   4   5   6   7   8   9   "   ,   "   4   4   "
             2232    222c    3534    3736    3938    2c22    3422    2234
0000240    ,   "   1   0   "   ,   "   1   1   "   ,   "   3   4   5   6
             222c    3031    2c22    3122    2231    222c    3433    3635
0000260    7   8   "   ,   "   0   0   1   "   ,   "  サ  **  **  ン  **
             3837    2c22    3022    3130    2c22    e322    b582    83e3
0000300   **  プ  **  **  ル  **  **  2  **  **                       "
             e3b3    9783    83e3    efab    92bc    2020    2020    2220
0000320    ,   "   2   0   1   5   1   2   0   9   "  \n 032            
             222c    3032    3531    3231    3930    0a22    001a        
0000335
$

作成ジョブの概要

今回はファイルの読み込みにtFileInputDelimitedコンポーネントは使わずtFileInputFullRowコンポーネントを使います。このコンポーネントはテキストの1行を1データとして入力し後続のコンポーネントへ渡すためのものです。後続のコンポーネントには文字コード置換させるためのtReplaceコンポーネントを使います。
通常の文字コード置換であればtReplaceコンポーネントの後続にtExtractDelimitedFieldsコンポーネントでデータを1行表現からCSV区切り表現へ変換するもので受けて最終的にtFileOutputDelimitedでファイル出力すればいいのですが、その状態でジョブを実行するとEOFが含まれている行が空行として無駄に出力されてしまいます。
これで特に問題があるわけではないのですが、綺麗にしたいのでtReplaceコンポーネントとtExtractDelimitedFieldsコンポーネントの間にもう一つtFilterRowコンポーネントを挟んで文字置換後に空行の場合は出力しないというものを追加した形でジョブを作成してちょっとスマートにしたいと思います。

実際にジョブを作成してみる

完成形は以下のような感じになります。
cm_blog_7_2

tFileInputFullRow の基本設定でEOFの含まれたCSVを指定します。
cm_blog_7_3

次に tReplace の基本設定で詳細モードにチェックし、正規表現パターンを登録します。ソースは tFileInputFullRow の line を指定し、パターンとして new String(Character.toChars(0x1a))を指定します。(置換後の部分は""に)
cm_blog_7_4

次に tFilterRow の基本設定で条件を指定します。
tFilterRowコンポーネントは、指定したカラムの条件に一致する行だけを抽出するものです。使い方はフィルタリング条件のカラム名を「入力カラム」に、比較条件を「オペレータ」に、比較値を「値」に入力します。
cm_blog_7_5

あとはtFilterRowで条件がマッチした行を後続の tExtractDelimitedFields に渡して最終的に tFileOutputDelimited でCSVを書き出してあげれば完成です。

ジョブを実行する

cm_blog_7_6
正常にジョブが終了しました。
Sublime Textでみた状態SUBが取り除かれていることが確認できます。
cm_blog_7_7
一応odコマンドでコードとキャラクタ表示をさせたものでも確認。最後の1aが正しく取り除かれていることが確認できます。

$ od -cx eof_sample_trance.csv 
0000000    "   s   a   m   p   l   e   1   "   ,   0   ,   "   0   1   "
             7322    6d61    6c70    3165    2c22    2c30    3022    2231
0000020    ,   "   A   A   "   ,   "   1   "   ,   "   2   0   1   5   1
             222c    4141    2c22    3122    2c22    3222    3130    3135
0000040    1   2   0   "   ,   "   9   8   7   6   5   4   "   ,   "   3
             3231    2230    222c    3839    3637    3435    2c22    3322
0000060    2   "   ,   "   1   0   "   ,   "   1   2   "   ,   "   3   4
             2232    222c    3031    2c22    3122    2232    222c    3433
0000100    5   6   7   8   "   ,   "   0   0   1   "   ,   "  サ  **  **
             3635    3837    2c22    3022    3130    2c22    e322    b582
0000120   ン  **  **  プ  **  **  ル  **  **  1  **  **                
             83e3    e3b3    9783    83e3    efab    91bc    2020    2020
0000140        "   ,   "   2   0   1   5   1   2   0   9   "  \n   "   s
             2220    222c    3032    3531    3231    3930    0a22    7322
0000160    a   m   p   l   e   2   "   ,   0   ,   "   0   1   "   ,   "
             6d61    6c70    3265    2c22    2c30    3022    2231    222c
0000200    B   B   "   ,   "   1   "   ,   "   2   0   1   5   1   2   0
             4242    2c22    3122    2c22    3222    3130    3135    3032
0000220    2   "   ,   "   4   5   6   7   8   9   "   ,   "   4   4   "
             2232    222c    3534    3736    3938    2c22    3422    2234
0000240    ,   "   1   0   "   ,   "   1   1   "   ,   "   3   4   5   6
             222c    3031    2c22    3122    2231    222c    3433    3635
0000260    7   8   "   ,   "   0   0   1   "   ,   "  サ  **  **  ン  **
             3837    2c22    3022    3130    2c22    e322    b582    83e3
0000300   **  プ  **  **  ル  **  **  2  **  **                       "
             e3b3    9783    83e3    efab    92bc    2020    2020    2220
0000320    ,   "   2   0   1   5   1   2   0   9   "  \n                
             222c    3032    3531    3231    3930    0a22                
0000334
$

まとめ

EOFを取り除くということ自体はあまり需要があるかどうかはわかりませんが、EOF以外にもさまざまな制御コードを取り除く必要があるケースも出てくるかと思いますので、その際はtFilterRowの条件部分を変更すれば利用用途はあるのかなと思います。