« ◇mute専用リモコン | トップページ | ◇ガンガンとガタンガタン;日本語のオノマトペが持つ情報 »

◇sed,perlでプログラムソースを変更するメモ

すぐ忘れるので
雛型の意味を込めて

perlでこんな感じでテキストファイル書き換えができます。

単語置き換え:
  perl -0pi -e 's/(\W+)(word)(\W+)/$1other-word$3/mg'  sample.c
perlの利点は何と言っても部分パターン(上の例では$1,$3)を参照できる点です。

sedでこんな感じで行追加、行削除ができます。

行追加:
  sed -i -e '/^#include <stdio.h>/a #include "<string.h>"' sample.c
行削除:
  sed -i -e '/^#include <string.h>/d' sample.c

perl,sedとも改行の取り扱いはとてつもなく複雑で難しく訳が分からなくなりますので注意してください。

 指定行の前後に行を追加(sedで)

ここではsedを用いて特定パターンの行の後ろまたは前に複数行を追加する例を示します。

ターゲットファイルの内容を置き換えるsedコマンドの形式は次の様になります。

sed -i -e '変更処理記述' ターゲットファイル

-iオプション指定をするとターゲットファイを置き換えます。
-eで与える変更処理記述は
 '/行パターン/a 後ろに追加する行'
 '/行パターン/i 前に追加する行'
です。
複数行を追加する場合は\(逆スラッシュ)を置いて複数行記述します。
パータンには正規表現が使用できます。^は行の先頭,$は行末を表します。

sed -i -e \
'/^#include <stdio.h>/a #include "hiLog_forC.h" \
#define LOG() hiTRACE_TO("/tmp/sample","IN") \
#define LOGO() hiTRACE_TO("/tmp/sample","OUT") '\
 sample.c

sed -i -s \
'/^#include <stdio.h>/i #include "bbb.h"' sample.c

これを次の記述に適用すると

#include "aa.h"
#include <stdio.h>

以下の記述が得られます。

#include "aa.h"
#include "bbb.h"
#include <stdio.h>
#include "hiLog_forC.h" 
#define LOG() hiTRACE_TO("/tmp/sample","IN") 
#define LOGO() hiTRACE_TO("/tmp/sample","OUT") 

行パターンは正規表現が用いられます。
ただし、"^":行の先頭,"$":行の最後以外は使わない方が良いと思っています。

 指定行の削除(sedで)

d指定で行を削除することができます。

sed -i -e '/パターン/d' ターゲットファイル
次の記述で、先の項で追加した行が削除されます。
sed -i -e '/^#include "hiLog_forC.h"/d' sample.c
sed -i -e '/^#define LOG()/d' sample.c
sed -i -e '/^#define LOGO()/d' sample.c
sed -i -e '/^#include "bbb.h"/d' sample.c

 単純置き換え(sedで)

正規表現を用いた単純置き換えも可能です。
ただし、"^":行の先頭,"$":行の最後以外は使わない方が良いと思っています。

sed -i -e 's/パターン/置き換え文字列/g' ターゲットファイル
sed -i -e 's/^{$/{LOG();/g'  sample.c


 行端を認識させる準備(perl)

正規表現で$は行端を意味しますが、perlでもsedでもCR/LFやCRには対応しません。
そのため、最初に次の手続を実施した方が安全です。

perl -0pi -e 's/\r//mg'  sample.c
以下の例ではこの処置を取らず行端を[\n\r]+または(\n|\r\n|\r)でマッチさせています。

 指定行の前後に行を追加(perl)

perlには行を追加する機能はありません。
文字列の置き換えを用います。
perlでの基本文字列置き換えコマンド形式は次の形をしています。

perl -0pi -e 's/置き換え元パターン/置き換え後パターン/mg'  対象ファイル
置き換え元パターンは正規表現です。
sedと異なり$はLF一個の場合のみ有効(CRLFにはマッチしない)ことに強く留意する必要があります。
行末としての$は使えないと考えた方が安全です。
置き換え後パターンは正規表現ではありませんが、(などにエスケープが必要であることに注意が必要です。
マッチしたパターンを置き換え後パターンで参照するには$&を用います。
#---- 後ろに追加
perl -0pi -e  \
's/#include <stdio.h>/\
$&\
#include "hiLog_forC.h"\
#define LOG\(\) hiTRACE_TO\("\/tmp\/sample","IN"\)\
#define LOGO\(\) hiTRACE_TO\("\/tmp\/sample","OUT"\)/mg' \
 sample2.c
#---- 前に追加
perl -0pi -e  \
's/#include <stdio.h>/\
#include "bbb.h"\
$&/mg' \
 sample2.c
これを次の記述に作用させると
#include "aa.h"
#include <stdio.h>
次の結果が得られます。
#include "aa.h"
#include "bbb.h"
#include <stdio.h>
#include "hiLog_forC.h" 
#define LOG() hiTRACE_TO("/tmp/sample","IN") 
#define LOGO() hiTRACE_TO("/tmp/sample","OUT") 

 単語パターン置き換え(perl)

単語を置き換える場合、対象箇所の前後が単語を構成する文字以外であることのチェックが必要です。
ここではperlで正規表現を用い置き換えを実施します。

perlでの基本文字列置き換えコマンド形式は次の形をしています。

perl -0pi -e 's/置き換え元パターン/置き換え後パターン/mg'  対象ファイル

置き換え元パターンは正規表現で記述します。
特殊な文字セットとして次のようなものが指定できます。

  \w:単語用文字。[a-zA-Z_][a-zA-Z_0-9]*を拡張したもの
  \W:\w以外の文字
  \s:[ \t\b\f\n\r]などの改行を含む空白文字
  \S:\s以外の文字

例えば abc に合致し前後に別の文字があるパターン(xabcなど)に合致しないパターンは次のように指定できます。

   W+abcW+

パターンは()を用いて分割し、分割されたそれぞれにマッチした部分文字列を置き換え後パターンで参照することができます。

   (W+)(abc)(W+) : (W+)第1パターン (abc) 第2パターン (W+)第3パターン
置き換え後パターンでは$1,$2,$3...でマッチした部分文字列を参照できます。例えば
  @abc# なら $1:"@"  $2:"abc"  $3:"#"
となります。

"funcB"を"funcBB"に変更する記述は次の物になります。
perl -0pi -e 's/(\W+)(funcB)(\W+)/$1funcBB$3/mg'  sample.c

 複数行に渡る単純置き換え(perl)

例えば2行に渡る

int* funcA(int arg1,char* arg2)
{
   funcB();
}
を次のように置き換える(この例では"//"を追加)
int* funcA(int arg1,char* arg2)
{//
   funcB();
}
には、次のように記述します。
perl -0pi -e \
's/^(int\* funcA\(int arg1,char\* arg2\)[\n\r]+\{)(\n|\r\n|\r)/$1\/\/$2/mg' \
  sample.c

この例で[\n\r]+および(\n|\r\n|\r)はLF,CRLFに両対応するものです。

 複数行に渡るパターン置き換え(perl)

前の例では関数"funcA"に限定した形でしたがこれを非特定の関数に拡大します。

perl -0pi -e \
's/((\w+[*&]*\s+)*\w+\([^)]*\)\s*)(\{)(\n|\r\n|\r)/$1\{LOG();$4/mg' \
 sample.c
この例では次のようなパターンを使っています。
   (                                            $1
      (\w+[*&]*\s)*  int *,short & など戻り値型    $2
      \w+            関数名
      \([^)]*\)      ( ... )
      \s*             改行を含む空白文字列
   )
   (\{)               {                         $3
   (\n|\r\n|\r)      改行 LF,CRLF ,CR           $4

マッチしたパターンの参照番号はネストとは関係なく定義での並び順になります。
この例では$2を参照すると関数の戻り値の型が得られます。
$4はオリジナルにあった改行パターンです。

置き換えパターン"$1\{LOG();$4"は関数開始直後に"LOG();"を置く形です。

次のように置き換わります。

ーーー 置き換え前
void
funcB(int arg1,char* arg2)
{
   xfuncB();
}
const int* funcC(int arg1,char* arg2)
{
   funcD();
}
void funcF(int arg1,char* arg2)
{//
   funcX();
}
ーーー 置き換え後
void
funcBB(int arg1,char* arg2)
{LOG();                      <-- "LOG();"追加
   xfuncB();
}
const int* funcC(int arg1,char* arg2)
{LOG();                      <-- "LOG();"追加
   funcD();
}
void funcF(int arg1,char* arg2)
{//                        <-- 追加されない(マッチしないため)
   funcX();
}

|

« ◇mute専用リモコン | トップページ | ◇ガンガンとガタンガタン;日本語のオノマトペが持つ情報 »

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/489055/71625320

この記事へのトラックバック一覧です: ◇sed,perlでプログラムソースを変更するメモ:

« ◇mute専用リモコン | トップページ | ◇ガンガンとガタンガタン;日本語のオノマトペが持つ情報 »