PAGE TOP

取り組み

印刷する

gawkを使う《その2》

さぼ郎
文字加工

沢山のコードのデータがあって、重複をカウントしながらユニークにするような処理を考えてみます。

【A】のデータ

1381692073S00743139
1300000277S01011186
1300000277S01011186
1300000277S01011186
1300000277S01011186
1300000277S01011186
1300000277S01011186
1300000277S01011186
1300000277S01011186
1300000277S01011186
1300000277S01011186

このようなデータが「85,889件」あったとします。

【B】のデータ

74313900
101118600
101118600
101118600
101118600
101118600
101118600
101118600
101118600
101118600

同じカテゴリのデータですが、ちょっと趣旨が異なるコードのデータが「36,448件」あります。

【ミッション
ミッションは、データAとデータBをマッチングして、それぞれを比較して件数の多い方を採用するとします。

【1】ステップ1
まず、コードは並び替えられていてデータAもデータBも出現するならば、データ並びの順に出現するように整理されているものとします。
そんな生理にはExcelは抜群の能力を発揮します。

データの性質を見てみると
1381692073S00743139 ー> 74313900
1300000277S01011186 ー> 101118600
となっていますので、カウントしながらデータAを加工していきます。

{
if(length($0)>9){
ss=substr($0,length($0)-6,7);
sub(/^0+/,"",ss);
$0=ss "00";
}

if($0!=old){
if(NR>1)
print old "t" cc;
cc=1;
}else
++cc;

old=$0;
}
END{
print old "t" cc;
}

【説明】
length($0)>9
length は文字列の長さを返します。
$0 は、取り込んだ文字列そのものを示します。
「$0が9文字より長ければ」ということ。

デフォルトは半角スペースがセパレータだったと思います。
「$0」と指定すればセパレータとは関係なく、取り込んだ文字列そのものを意味することになります。
カンマとかタブでセパレートする場合は、先頭に「BEGIN」を入れて宣言する必要があります。
これについては、いずれ機会を見て説明します。

ss=substr($0,length($0)-6,7);
substr は、文字列から切り出す関数です
substr(n1,n2,n3)  のように指定します。
n1:対象とする文字列
n2:切り出す位置
n3:切り出す文字数
ss=substr($0,length($0)-6,7)
$0:取り込んだ文字列そのもの
length($0):文字列の長さ

データAの文字列長は19文字あるので9文字より長いです。
で、「19-6=13」ですので13文字から7文字を取り出します。

1381692073S00743139 -> 0743139

sub(/^0+/,"",ss); は、正規表現を使っています。
^0+」というのは、切り出した文字列「ss」の頭から「0」が一つ以上あれば、その「0」を無くすようにしています。

$0=ss "00"; は、そもそもの文字列である「$0」に、頭に「0」があれば、その「0」を取り除きながら、末尾には「00」を付けて元の「$0」を書き換えています。文字列の結合は、VBでは「&」、Pythonなどでは「+」を使いますが、awkは並べて書くだけです。

if($0!=old){
$0 が 変数「old」と異なる(「!=」)ならば、以下の処理をする
この手の書き方は、ストリームエディタでは必須の処理になります。本来、ストリームエディタは、取り込んだ行データを対象に加工しますが、1行前のデータを覚えておいて、次のデータと比較するような場合は、ループの入口で比較をし、出口で今読み込んだデータで更新する必要があります。

if(NR>1)
NR とは予約語で、読み込んだ文字列の数を示します。
NR>1 としているのは先頭行を無視しています。
つまり2行目以降という意味です。
なぜなら、先頭行においては変数oldは空だから「!=」が成立してしまいます。

print old "t" cc;
print(標準出力に)するのは、「old」です。なぜなら、読み込む文字列が変わったら、一つ前の文字列とカウントした件数を表示するからです。
cc=1;
ここでカウンターの「cc」を1に戻します。

}else
この「else」は、文字列が同じならばということ。
++cc;
カウンター「cc」をインクリメントします。

old=$0;
変数「old」に必ず「$0」を入れるのが鉄則です。
1行ずつ読み込みながら、文字列の変化を確認しています。

END{
print old "t" cc;
}
一番最後のデータを読み終わると、「END」の処理をします。
今回は説明していませんが、対になる予約語に「BEGIN」があります。「BEGIN」も「END」も、処理の始めと終わりに1回だけ参照されます。
この処理を入れないと最終の文字列とカウントを取り損ないます。

74313900:1
101118600:127
104258000:106
107761500:77

となり、右列のカウント数の総計が「85,889」となり、カウント数は合致しています。
同じスクリプトでデータBを処理すると、

74313900:1
101118600:25
104258000:28
107761500:76

となり、カウント数の総計が「36,448」であることが確認できます。

わずか18行のスクリプトで、これだけのことが一瞬で処理できるのだから、「awk」のテキスト加工の能力は、並外れていると思います。

最近では人口頭脳のからみで「Python」を眼にします。あまり眼にはしませんがGoogleが開発した「Go言語」などにも興味がありますが、「awk」の実用性の高さも少しずつ、説明していきたいと思っています。

【ステップ2】データAとデータBを比較して並びを変える
「ステップ2」はExcelのVBAで行います。
件数が少なければExcelの「if文」を使えばいいかもしれませんが、件数が多ければVBAの出番です。

人力でやるよりも、パソコンの自動処理や、機械を使うのが今時の企業人が求められていることなのでしょう。

そして、向かうところは無人化(AI+ロボット)なのですから、ブラックな話です。ブラックといっても「あくどい」という意味ではなく「ユーモア」の方です。

しかし、無人化が進めば人間の労働は限定されてきます。そんな社会になれば、労働にありつけないヒトは国家の責任で社会保障で生活するようになるのでしょうか。あるいは、敢えて効率を落として人間の働く場面を創出していくのでしょうか。
自組織を “主体” に置いて、いかに有利な事業活動を展開していくかを追い求めていくと、次第に過度な “競争原理” へと突き進む傾向が強くなる。
本日、目にした経営学のコラムです。過度な競争原理はコスト削減を必要以上に追求することとなりますし、あるいは、競争優位を求めて東芝の原子力発電やシャープの太陽発電のような、経営判断の誤りにつながるリスクもあります。

大将の判断ミスで大負けを喫したといえば、何と言っても「ミッドウェー海戦」です。浮沈をかける経営陣の判断とは、ここから学ばなければ、仮に勝ったとしても、それは単なる運でしか無いと思います。

となれば浮沈をかけないイノベーションを追い求めるほうが賢明のような気がします。いま、まさにブロックチェーンで示された「分散台帳管理技術」を徹底的に研究してみようと思っています。

RPA
VBAの記事にリンク ↑

もう、「RPA(Robotic Process Automation)」は、ちっとトレンド落ちという感じで、先行者利益にはありつけないような状態になりつつあるようですが、「汎用」ということで、どこまで、通用するのかは不明です

キーワード