004923 ランダム
 ホーム | 日記 | プロフィール 【フォローする】 【ログイン】

ricefish

ricefish

【毎日開催】
15記事にいいね!で1ポイント
10秒滞在
いいね! --/--
おめでとうございます!
ミッションを達成しました。
※「ポイントを獲得する」ボタンを押すと広告が表示されます。
x
2007年09月23日
XML
#!/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秒


PR

プロフィール

ricefish

ricefish

カレンダー


© Rakuten Group, Inc.