• ベストアンサー

UNIXでのプログラムその2

UNIXでのシェル/AWK/SEDなどで以下のような 処理をおこないたいのですがいい方法を教えて下さい。 以下のような変換をやりたい。 MED1 = ( AMED1 NOT WIN ) interact (( BME1_1 OR ACON ) OR TH1 )   ↓ MED1_1 = AMED1 NOT WIN MED1_2 = BME1_1 or ACON MED1 = MED1_1 interact MED1_2 OR TH1

質問者が選んだベストアンサー

  • ベストアンサー
  • wolv
  • ベストアンサー率37% (376/1001)
回答No.6

若干修正: No4のソースで、消し忘れの行と冗長部分を削除しました。 #!/bin/awk -f { str = $0 NVAR=0 varbase=$1 #shori str=par_replace(str,varbase) #output for(i=1;i<=NVAR;i++){ print VARNAME[i]" = "VARVAL[i] } print str } function par_replace(str,varbase){ while(match(str,/\([^()]*\)/)){ NVAR++ VARNAME[NVAR]=varbase"_"NVAR VARVAL[NVAR]=substr(str,RSTART+1,RLENGTH-2) sub(/\([^()]*\)/," "VARNAME[NVAR]" ",str) } return str }

Kasaoka-Taroh
質問者

お礼

ばっちり動きました。 感謝!感謝!です。 これを参考にあとは自分なりに拡張させていけそうです。 本当にお世話になりました。

その他の回答 (5)

  • wolv
  • ベストアンサー率37% (376/1001)
回答No.5

PS: 回答1でlintがどうこういいましたが、回答3でnotnotさんが言われたyaccをlintだと勘違いして回答してました。ごめんなさい。 検索しても適当なページが見つからないわけです^^;

  • wolv
  • ベストアンサー率37% (376/1001)
回答No.4

回答1で書いた仕様とちょっとちがいますが、汎用性のあるスクリプトができました。 「(」「括弧以外の連続」「)」の部分を順次変数に置き換えます。 #!/bin/awk -f { str = $0 NVAR=0 varbase=$1 #shori str=par_replace(str,varbase) for(i=1;i<=NVAR;i++){ VARVAL[ivar]=par_replace(VARVAL[ivar],VARNAME[ivar]) } #output for(i=1;i<=NVAR;i++){ print VARNAME[i]" = "VARVAL[i] } print str } function par_replace(str,varbase){ FLAG=0 while(str ~ /\([^()]*\)/){ match(str,/\([^()]*\)/) NVAR++ VARNAME[NVAR]=varbase"_"NVAR VARVAL[NVAR]=substr(str,RSTART+1,RLENGTH-2) sub(/\([^()]*\)/," "VARNAME[NVAR]" ",str) FLAG=1 } return str } #標準のawkではmatchという関数が使えないかもしれません(手元の本には、matchはnawkで実装されていると書いてあります) 実行例(上記scriptをpar_repl.awkとすると) awk -f par_repl.awk [ENTER] MED1 = ( AMED1 NOT WIN ) interact (( BME1_1 OR ACON ) OR TH1 )[ENTER] MED1_1 = AMED1 NOT WIN MED1_2 = BME1_1 OR ACON MED1_3 = MED1_2 OR TH1 MED1 = MED1_1 interact MED1_3 Ctrl+D (実行例終わり)

  • notnot
  • ベストアンサー率47% (4846/10257)
回答No.3

数式のコンパイル時の構文解析のようなことをやりたいのであれば、一般には、yacc もしくは bison という字句解析プログラム生成ツールを使います。 それらを使わないでも、perl か ruby あたりを使えば出来るでしょう。方針は#1の書かれた方法でいいと思いますが、多重のカッコ処理が難しそうですね。

参考URL:
http://guppy.eng.kagawa-u.ac.jp/~kagawa/2000/SysProg/bison-1.2.8/bison-ja_toc.html
  • terra5
  • ベストアンサー率34% (574/1662)
回答No.2

こういうのをきっちり汎用的に作ると大変なので、 特定パターン専用にいくつか作って、漏れたのを手で修正ってのはよくやります。 だいたいが一時的に必要なだけですので。 とりあえず、 a = ( b ) interact ( ( c ) d ) の形の=,(,),interactをキーに a_1 = b a_2 = c a = a_1 interact a_2 d の形に処理するのをperlで書きましたので、 あとは必要なパターンだけ修正したのを作って使ってください。 正規表現だけわかれば、なおせると思います。 (awkは正規表現のでの置換が非力なので、こういう場合はsedやperl等使います) あと、タブには非対応なので、必要に応じて" *"の部分を"[ \t]*"に変えてください。 while(<>) { if ( $_ =~ /^ *\w *= *[(] *.+ *[)] interact *[(] *[(] *.+ *[)] *.+ *[)] *$/ ) { chop; $v1 = $v2 = $v3 = $v4 = $_; $v1 =~ s/^ *(\w) *=.*$/$1/; $v2 =~ s/^ *\w *= *[(] *(.+) *[)] *interact *.*$/$1/; $v3 =~ s/^ *\w *= *[(] *.+ *[)] *interact *[(] *[(] *(.*) *[)] .*$/$1/; $v4 =~ s/^ *\w *= *[(] *.+ *[)] *interact *[(] *[(] *.* *[)] *(.+) *[)] *$/$1/; printf("%s_1 = %s\n", $v1, $v2); printf("%s_2 = %s\n", $v1, $v3); printf("%s = %s_1 interact %s_2 %s\n", $v1, $v1, $v1, $v4); } else { print $_; } }

  • wolv
  • ベストアンサー率37% (376/1001)
回答No.1

これは、たぶん「字句解析」だか「構文解析」と呼ばれる処理の一種で、awk・sedなどではなく、lintという処理系を使ってやるべき処理です。 (上記の文に含まれているキーワードを使ってWWWを検索してみましたが、適当なページが見つからなかったので、どこか語句の間違いがあるかもしれません。) awk・sedでもできないことはないでしょうが、やや複雑な処理になると思います。 さて、それでもとにかくawkやsedでやるとして、 実際の処理を具体的にしたいのですが、やりたい処理は、 ・「(」,「)」の前後には空白が省略されていることもありうる。 ・2つめの単語は「=」である。 ・ひとつめの単語を式の名前とみなせる ・式中に「(」「)」の組が出てきたばあいは、「式の名前_数値」という「変数」を新たに定義し、括弧と括弧に囲まれた部分を変数に置き換える。 ・式中に括弧がなくなるまで上記の処理を再帰的に行う。 ということでよいのでしょうか? また、上記の処理を行った場合、 "MED1 = ( AMED1 NOT WIN ) interact (( BME1_1 OR ACON ) OR TH1 ) " は、 "MED1_1 = AMED1 NOT WIN MED1_2_1 = BME1_1 or ACON MED1_2 = MED1_2_1 or TH1 MED1 = MED1_1 interact MED1_2" に変換されることになりますが、それでかまいませんか?

Kasaoka-Taroh
質問者

お礼

質問に全部答えたつもりだったのですが、 最後の質問に回答をもらしていました。 ここの書くのもおかしいのですが 他に方法がみつからなかったので、ここに書きます。 出力形式についても上記の形で問題ありません。

Kasaoka-Taroh
質問者

補足

ご検討ありがとうございます。 回答します。 ・「(」,「)」の前後には空白が省略されていることもありうる。   →今、処理しようとしているデータは 空白が必ずあるのですが、汎用性を考慮するとどちらでもという方が好ましいです。 ・2つめの単語は「=」である。     →これは必ずそうです。 ・ひとつめの単語を式の名前とみなせる     →これも必ずそうです。 ・式中に「(」「)」の組が出てきたばあいは、「式の名前_数値」という「変数」 を新たに定義し、括弧と括弧に囲まれた部分を変数に置き換える。     →これもその通りです。 ・式中に括弧がなくなるまで上記の処理を再帰的に行う。     →その通りです。 お手数かけて申し訳ありませんが、よろしくお願いします。 これができれば大変助かります。

関連するQ&A

  • UNIXのcshについて。

    ちょっとここに質問していいものか迷いましたが、 このカテゴリで質問させていただきます。 UNIXのCシェルで、あるシェル変数に1行分のデータが 読み込まれていて、これをいくつかのデータがタブ 区切りで入っています。 これを違う複数の変数に各データを切り分けて入れた いのですが、どうしたらいいかわかりません。 awkやsedという手を考えたのですが、あれはファイルから 読み込むので、できませんでした。 わかる方がいらっしゃればよろしくお願いします。

  • unixでの文字列置換方法

    UNIX上のテキストファイル内の以下で以下の様な置換をおこないたいのですが いい方法が思いつきません。どなたか教えて下さい。 cj = 5.0e-12   ↓ cj = 0 ”cj”の部分は特定のキーワードが入ります。方法は特に問いません。 awkかsedあたりでできるとメンテナンスもやりやすいのでいいかなという程度です。

  • UNIXのシェルスクリプト

    UNIXのシェルスクリプトで以下のようなことをやりたいのですがいい方法を教えて下さい。 ファイルの中にある文字列があります。 たとえば”CURREND_DIR” この文字列をシェルスクリプトでカレントのディレクトリパスに変換したいのですが いい方法が思いつきません。 set dir_data = ‘pwd‘ sed -e ’s/CURRENT_DIR/$dir_data’ ファイル名 でできるかなと思ったのですが、”CURRENT_DIR”が”$dir_data”に置換されてしまいます。 さらにdirパスが”/”で区切られていることも問題のようです。

  • UNIX sed

    UNIX初心者なのですが、 sedをつかって、行末を改良文字に変換する方法ってどのようにやるのですか? sed 's/$/\n/' では、行末をnにしてしまいます。 詳しい方教えてください!

  • UNIXでのプログラム

    UNIXでのシャルスクリプトでもAWKでもいいのですが以下のようなことがやりたいのですが、いい方法が思い つきません。どなたか教えて下さい。 テキストファイルがあり、そのファイル中の”//”という文字から行末までは削除したファイルを作りたい。 ”//”という文字列は文字列の途中にあるケースも前後にスペースが存在して単語として存在しているケースもあります。

  • コード変換を行う

    ある要件でレコード内のTAB+LFをLFに変換したいのですが、 プログラムは作成せず、シェルレベル(awk,sedレベル)で 処理したいのですが、有効な手段をご存知の方はいらっし ゃいませんでしょうか? よろしくお願いいたします。

  • UNIXでシェルスクリプトを作ることを始めましたが、まだ未熟者です。

    UNIXでシェルスクリプトを作ることを始めましたが、まだ未熟者です。 既存のスクリプトが複数あるのですが、 全てに対して同じ処理を入れ込む必要があります。 入れ込む内容はレイアウトを変更するだけ(awkで書く予定)なので簡単なのですが、 既存スクリプトに全て書き込むのは大変です。 また入れ込んだ処理内容に変更があったときに、全てのスクリプトに変更をひとつひとつ反映させるのは大変です。 入れ込む処理を別ファイルで作成しておいて、 既存スクリプトからはこのファイルを参照するだけにしたいのですが、 どのように書いたらいいのでしょうか?教えてください。

  • UNIX コマンドの練習方法について

    こんにちは、UNIX初心者です。 sed, awk などのUNIXコマンドを、OSをインストールせずに、現在のwindows 98SE のままで、 1.ブラウザ画面内で、どこかのサイトを利用して、   ブラウザ内で、UNIX or Linuxコマンドの練習できないかどうか? 2.みなさんは、どうやってUNIXコマンドをwindows上で、練習されてますか? 3.Linux を同マシンにインストールする場合、OS+作業領域の容量ザイズは、1GB? くらいでしょうか? ---------------------------------------------- 知人からは、windows98 のままで、Linux をインストールして、ダブルOS(デュアル)で、どうか? と言われております。 どなかた、教えてください。

  • UNIXで、とあるテキストに対して2文字区切りで改行をいれるには?

    UNIXのシェルスクリプトで、このような動作ができないものかどうか考えています。 あるテキストファイルの内容を、2文字ごとに区切って改行を入れるように加工する 例えば file1.txt が以下のような内容であれば --file1.txt-- 000092 027301 01 0263000001 2文字ずつ区切って改行を挿入したファイル --file2.txt-- 00 00 92 02 73 01 01 02 63 00 00 01 を生成したいと思います。 ここで元のファイルは必ず、半角の数字のみで構成されており、 1行の文字数は最低2文字以上あり、なおかつ奇数個の文字列は存在しないものとします。 awk や grep や sed を組みあわせて考えているのですが、 なかなか解決に至りません。 どなたかお知恵を拝借願います。

  • ある単語を含む行と、1つ前の行とを削除するシェル

    UNIX初心者です。 シェル(Korn)で、あるファイル中に、単語 "iwa"を含んだら、その行と、1つ前の行とを削除したいシェルを作りたいのです。  つまり、grep, sed, awk などで、"iwa"を含む行がみつかったら、その行(iwaを含む行)と、なおかつ、1行前の合わせて、2行を削除するシェルを作りたいのですが、行番号(NR?)などを使うのでしょうか? よろしく、お願いします。

専門家に質問してみよう