2007年09月23日
#!/usr/local/bin/ruby
def help
print <<-HELP_END
mkwild
mkwild [-1] [field1 field2 ...]
オプション
-1 最初のワイルドカードだけにする
説明
mkwild は、bash のパス名展開の [] とほとんど逆の操作(集約)を行います。
パス名展開では、例えば
aa[abc] --> aaa aab aac
という展開が行われますが、mkwild はこれとほとんど逆の操作(集約)
aaa aab aac --> aa[abc]
を行います。
オプション以外の引数が与えられた場合は、引数1個ずつをレコードとします。
オプション以外の引数がない場合、標準入力からレコードを取り込みます。
レコードの最初のフィールドとそれに続く区切り記号を除いた部分が全く同じ
文字列で、最初のフィールドが1文字違いのときに集約が行われます。
例をあげれば
aaa --> aa[ab] --+--> a[ab][ab]
aab |
aba --> ab[ab] --+
abb
となります。(例は最初のフィールドだけ表示しています)
ホワイトスペースだけのレコードがあれば消去されます。
オプション -1 は、集約を1段階だけ(前述の例で左から2番目のコラムまで)で
中断します。デフォルトでは、可能なかぎり繰り返します。
入力レコードの順番が、集約結果に影響する場合があります。
集約結果は、ソートされずに、入力の出現順番に出力されます。
[] の中の文字はソートされません。出現順番です。
[] の中の文字は重複は残されませんので、入力に全く同じレコードがいくつ
あっても、1個のときと出力は変わりません。
mkwild の行う集約は、パス名展開の「ほとんど」逆の操作ですが、次の点が
異なります。
1. bash のパス名展開は、* や ? の展開を行いますが、集約には関係ありません。
また、パス名展開で使うことのできる、文字クラスや - による文字の範囲での
指定は、集約には関係ありません。
2. bash のパス名展開は、ファイルが存在する場合だけ展開しますが、
集約は、ファイルの存在には関係ありません。
集約された [] の中には、入力に存在するものだけ含んでいます。
ファイルの存在と関係がないため、ファイル名以外の用途で使う事も可能です。
バグ
入力レコードの順番が、集約結果に影響する場合がありますが、異なる集約結果を
得るためには、mkwild の内部動作を考えて、入力を変更するしか方法がありません。
入力が sort されている場合、集約結果は人間にとって分かりやすい物であると
思います。
フィールドの区切り記号は、空白文字(ruby の \\s で [ \\t\\n\\r\\f])です。
例えば grep は、ファイル名を出力する場合のファイル名とマッチの出力の区切り
記号は ':' ですが、これと mkwild のフィールド区切り記号の整合が取れていません。
HELP_END
end
opt=Hash.new
ARGV.delete_if {|x| case x
when "-1" then opt[x]=true
when "-h","--help" then help;exit
end}
if ($*.size==0)
data=$stdin.readlines
else
data=$*
end
data.uniq!; data.each {|i| i.chomp!}; data.delete_if {|a| a=~/^\s*$/}
#最初のレコードとそれ以降を切り分けて Arrayにする
data=data.collect {|a| /^\s*([^\s]*)\s*(.*)/.match(a).to_a.values_at(1,2)}
data_size=0;
begin
data=data.inject([]) {|r,aa| a=aa[0]; j=0; wild=nil;
ri=(0...r.size).find {|ri|
if (aa[1]==r[ri][1])
b=r[ri][0]; i=j=0; wild=nil
until (i>=a.size || j>=b.size)
if (a[i]==b[j]) ;then i+=1;j+=1
elsif (wild) ;then j=b.size+1; wild=nil ##2個以上異なる
elsif (b[j]!=?[);then wild=[j,"["+b[j].chr+a[i].chr+"]"];i+=1;j+=1 ## make []
elsif (c=b.index(/\]/,j));then ## add to []
wild=[j..c,b[j...c]+(b[j..c].include?(a[i])?"":a[i].chr)+"]"];
i+=1;j=c+1
else j=b.size+1 ## [] が対応していない 通常の文字として処理
end;end ## until
wild && i==a.size && j==b.size; end}
if (ri)
r[ri][0][wild[0]]=wild[1];
else
r.push(aa)
end
r }
end while (!opt["-1"] && data_size!=(data_size=data.size))
s=data.collect {|a| a[0].size}.max
data.collect {|a| (a[1].size==0)?a[0]:sprintf("%-*s %s",s,a[0],a[1])}.each {|a| (a+"\n").display}
# end of mkwild
最終更新日
2007年09月25日 09時54分07秒