#!/bin/sed --unbuffered -f # # 使い道 スタックを使って短かいテキストの編集をする GNU sed 用のスクリプトファイル # 使い方(対話的に使う場合) # sed --unbuffered -f rpnedit.sed # # rpnedit.sed (ver. 0.76) --- a sed script to edit text with stack # Copyright (C) 2016 kabipanotoko # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # H g /\t/! {s/^/\n\t\t\t\t/}; # (タブでパターンスペースを 5 つに区切り、スタック内容の一時保管に使う場所に使う) # (処理の状態) \t (コマンドキュー) \t (スタック履歴1) \t (スタック履歴2) \t (現在のスタック) # M?\n cmd1\n...\ncmdN \n...\n...\n... \n...\n...\n... \n...\n...\n... # M?: マクロ内部にいるかどうかの判定 #マクロの処理 /\n<<<$/ { s/\n<<<$// h #\t で区切られた 2 番目のセルと、最後のセルを交換し、最後のセルをマクロ命令たちを順次積み込むのに使う s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\(.*\)/\1\t\5\t\3\t\4\t\2/ :rmacro N # マクロ終了記号を読み取ると、それまで積んでおいた命令たちの実行を開始する /\n>>>$/ { s/\n>>>$// #\t で区切られた最後のセルを 2 番目のセルに戻すと、マクロ命令たちがそこに積まれている状態になる。 s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\(.*\)/\1\t\5\t\3\t\4\t\2/ b out } # マクロ終了記号以外を読取った場合は、さらに命令を読み込み続けるべくループする b rmacro } # マクロとして積んだ命令をひとつ実行し終えたときに跳ぶ場所。次のサイクルをここから始めれば、新な読み込みをしないですむ。 :domacro ######### 探索をするコマンド ######## # same? (2→1) レベル2 の内容が、レベル1 の内容と全く同じ場合に、T を積む /\nsame?$/{ s/\nsame?$// s/\([[:print:]]*\)\n\([[:print:]]*\)$/\2\n\1/ # レベル1 とレベル2 を交換 /\n\([[:print:]]*\)\n\1$/ { # レベル1 がレベル2 と同じなら s/[[:print:]]*\n[[:print:]]*$/1/ # どちらも削除して T を積む bout } s/[[:print:]]*\n[[:print:]]*$/0/ # もしそうじゃなきゃ、 bout # どちらも削除して 0 を積んで抜ける } # not /\nnot$/ { s/\nnot$// /\n0$/ { s/0$/1/; bout} s/\n[[:print:]]*$/\n0/ bout } # ^match? (2→1) レベル2 の内容が、レベル1 の内容で始まっている場合に、1 を積む /\n\^match?$/{ s/\n\^match?$// s/\([[:print:]]*\)\n\([[:print:]]*\)$/\2\n\1/ /\n\([[:print:]]*\)\n\1[[:print:]]*$/ { s/[[:print:]]*\n[[:print:]]*$/1/ bout } s/[[:print:]]*\n[[:print:]]*$/0/ bout } # match$? (2→1) レベル2 の内容が、レベル1 の内容で終わっている場合に、1 を積む /\n\match\$?$/{ s/\n\match\$?$// s/\([[:print:]]*\)\n\([[:print:]]*\)$/\2\n\1/ /\n\([[:print:]]*\)\n[[:print:]]*\1$/ { # レベル1 がレベル2 で終わっていたら s/[[:print:]]*\n[[:print:]]*$/1/ bout } s/[[:print:]]*\n[[:print:]]*$/0/ bout } # include? (2→1) レベル2 の内容が、レベル1 の内容を含んでいる場合に、その数を積む /\n\include?$/{ s/\n\include?$// s/\([[:print:]]*\)\n\([[:print:]]*\)$/\2\n\1/ # レベル1 とレベル2 を交換 h # パターンスペースをホールドスペースに保管し s/.*/0/ # パターンスペースの内容を 0 に変え x # パターンスペースを復元する。ホールドスペースは 0 になる :incloop /\n\([[:print:]]*\)\n[[:print:]]*\1[[:print:]]*$/ { # レベル1 がレベル2 を含んでいたら s/\n\([[:print:]]*\)\n\([[:print:]]*\)\1\([[:print:]]*\)$/\n\1\n\2\3/ # レベル2からマッチ部分を削除 x # パターンスペースを避難させてからホールドスペースからカウンターを呼び出す # 数を 1 だけたす /9$/ { s/^9$/10/;s/^19$/20/;s/^29$/30/;s/^39$/40/;s/^49$/50/; s/^59$/60/;s/^69$/70/;s/^79$/80/;s/^89$/90/; b inc1add } s/^\([1-9]\{0,1\}\)8$/\19/; s/^\([1-9]\{0,1\}\)7$/\18/; s/^\([1-9]\{0,1\}\)6$/\17/; s/^\([1-9]\{0,1\}\)5$/\16/; s/^\([1-9]\{0,1\}\)4$/\15/; s/^\([1-9]\{0,1\}\)3$/\14/; s/^\([1-9]\{0,1\}\)2$/\13/; s/^\([1-9]\{0,1\}\)1$/\12/; s/^\([1-9]\{0,1\}\)0$/\11/; :inc1add x # カウンターをホールドスペースに、戻し避難させてあったものをパターンスペースに戻す bincloop } s/\n[[:print:]]*\n[[:print:]]*$// # レベル2 とレベル1を削除して G # ホールドスペースにあるカウンターをレベル1 としてパターンスペースに追加 bout } ######## 論理演算 ###### # or (2→1) レベル2、レベル1 のいずれかが真なら 1 を積む。 # つまり、レベル2、レベル1 のいずれもが 0 でない限り 1 を積む。 /\nor$/ { s/\nor$// /\n0\n0$/! {s/\n[[:print:]]*\n[[:print:]]*$/\n1/; bout} # レベル2 とレベル1 のどちらも 0 というわけでなければ s/\n[[:print:]]*\n[[:print:]]*$/\n0/; bout # どちらも 0 なら } # and (2→1) レベル2、レベル1 のいずれもが真なら 1 を積む。 # つまり、レベル2、レベル1 のいずれかが 0 なら 0 を積み、他の場合は 1 を積む。 /\nand$/ { s/\nand$// /\n0\n[[:print:]]*$/ { s/\n0\n[[:print:]]*$/\n0/; bout } /\n[[:print:]]*\n0$/ { s/\n[[:print:]]*\n0$/\n0/; bout } s/\n[[:print:]]*\n[[:print:]]*$/\n1/; bout } ######## 条件による制御 ######## ##if /\nif$/ { s/\nif$// # レベル2 が 0 ならば、レベル 2 と レベル1 を削除 /\n0\n[[:print:]]*$/ { s/\n0\n\([[:print:]]*\)$// ; bout} # それ以外ならば、レベル 2 だけを削除 s/\n[[:print:]]*\n\([[:print:]]*\)$/\n\1/ bout } ##ifelse /\nifelse$/ { s/\nifelse$// # レベル3 が 0 ならば(else のときならば)、レベル 3 と レベル 2 を削除(レベル 1 だけ残す) /\n0\n\([[:print:]]*\)\n\([[:print:]]*\)$/ { s/\n0\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2/;bout } # それ以外ならば(if のときならば)レベル 1 を削除 s/\n[[:print:]]*\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\1/ bout } #ifif # 6 5 4 3 2 1 (レベル) # true true A1 A2 A3 A4 ifif → A1 # true false A1 A2 A3 A4 ifif → A2 # false true A1 A2 A3 A4 ifif → A3 # false false A1 A2 A3 A4 ifif → A4 # ただし false とは 0 のことで, true とは 0 以外の文字列のこと /\nifif$/ { s/\nifif$// # レベル6 とレベル5 がともに 0 ならば(つまり false false ならば)、レベル 1 だけ残す /\n0\n0\n[[:print:]]*\n[[:print:]]*\n[[:print:]]*\n[[:print:]]*$/ { s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\6/ bout } # レベル5 が 0 ならば(レベル 6 は 0 でないので、true false)、レベル 3 だけ残す /\n0\n[[:print:]]*\n[[:print:]]*\n[[:print:]]*\n[[:print:]]*$/ { s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\4/ bout } # レベル6 が 0 ならば(レベル 5 は 0 でないので、false true)、レベル 2 だけ残す /\n0\n[[:print:]]*\n[[:print:]]*\n[[:print:]]*\n[[:print:]]*\n[[:print:]]*$/ { s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\5/ bout } # それ以外はどちらも 0 でないので、true true だからレベル 4 だけを残す s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\3/ bout } #case3 # A1 A1 A2 A3 ifif に同じ # 5 4 3 2 1 (レベル) # true false|true A1 A2 A3 → A1 # false true A1 A2 A3 → A2 # false false A1 A2 A3 → A3 /\ncase3$/ { s/\ncase3$// # レベル5 もレベル6 も false なら レベル 1 のみ残す /\n0\n0\n[[:print:]]*\n[[:print:]]*\n[[:print:]]*$/ { s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\5/ bout } # レベル5 が false ならば(レベル4 はtrue のはずだから)レベル 2 のみ残す /\n0\n[[:print:]]*\n[[:print:]]*\n[[:print:]]*\n[[:print:]]*$/ { s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\4/ bout } # それ以外はレベル 5 もレベル4 も true だから、レベル 3 のみ残す s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\3/ bout } # array->procedure コマンドは、デリミタの置換を行うコマンドで、先頭に3つ続いた任意の文字 # をデリミタと解釈し、その文字列が出てきた箇所ですべて ||| に置換する。 # procedure はコマンド・キューに積まれた時点で、文字列とコマンドに分解され、順次実行される。 /\narray->procedure$/ { h # ***swap***rolls # 1 2 3 4 5 6↓ s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\n\([[:print:]]*\)\narray->procedure$/\6/ #s/\*\*\*/|||/g :n2p /^\([^|]\)\1\1\(.*\)\1\1\1/ { s/^\([^|]\)\1\1\(.*\)\(\1\1\1\)/\1\1\1\2|||/ bn2p } s/^\([^|]\)\1\1/|||/ H # ***swap***rolls |||swap|||array->procedure g # ↓ ↓ # 1 2 3 4 5 6 7 s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\n\([[:print:]]*\)\narray->procedure\n\([[:print:]]*\)$/\1\t\2\t\3\t\4\t\5\n\7/ bout } # A B ntimes コマンド A を B 回繰り返して実行する(A が文字列なら B 回同じものが積まれる) # ただし、0 <= B < 100 # command \n ntimes \n "ntimes" # ↓ ↓ ↓ /[[:print:]]\{1,\}\n[[:digit:]]\{1,2\}\nntimes$/ { s/\nntimes$// # 0 回は無視 /\n0$/ { s/\n[[:print:]]*\n[[:digit:]]*$// b out } :ntimes # 1 2 3 4 5 6 7 # \t \t \t \t # macro? commands record record <------------- stack -----------> # ... \n command \n digit # ↓ ↓ ↓ ↓ ↓ ↓ ↓ s/\(.*\)\n\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\n\([[:print:]]*\)\n\([[:digit:]]\{1,2\}\)$/M\n\2\t\n\7\3\t\4\t\5\t\6\n\7\n\8/ #(前行に対するコメント)コマンドキューの中身に対する置換が \n\7\3 の順になっているのは、コマンドキューに残りコマンドがある場合のことを考えてのことだ。ここで扱われる ntimes コマンド配下の(ゆゑに繰り返し実行されるべき)コマンドたちは、コマンドキューに元から残っていたコマンドたちに先がけて実行されることが期待されているのである。 /0$/ { s/\n10$/\n9/;s/\n20$/\n19/;s/\n30$/\n29/;s/\n40$/\n39/;s/\n50$/\n49/; s/\n50$/\n49/;s/\n60$/\n59/;s/\n70$/\n69/;s/\n80$/\n79/;s/\n90$/\n89/; b count } s/\n\([1-9]\{0,1\}\)1$/\n\10/; s/\n\([1-9]\{0,1\}\)2$/\n\11/; s/\n\([1-9]\{0,1\}\)3$/\n\12/; s/\n\([1-9]\{0,1\}\)4$/\n\13/; s/\n\([1-9]\{0,1\}\)5$/\n\14/; s/\n\([1-9]\{0,1\}\)6$/\n\15/; s/\n\([1-9]\{0,1\}\)7$/\n\16/; s/\n\([1-9]\{0,1\}\)8$/\n\17/; s/\n\([1-9]\{0,1\}\)9$/\n\18/; :count /\n0$/! b ntimes s/\n[[:print:]]*\n[[:digit:]]*$// s/\(.*\)\n\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)/M\n\2\t\3\t\4\t\5\t\6/ b out } # レベル2 にある文字列をレベル1 から探し、 # 最初に見つかったものの前(splitb)または後(splita)または前後(splitba)でレベルを分割する。 /\t.*\n[[:print:]]\{1,\}\n[[:print:]]\{1,\}\nsplit\([ab]\|ba\)$/{ # 検索パターンと文字列を交換し、文字列の前に空のスタック(文字列前半)を挿入 s/\n\([[:print:]]*\)\n\([[:print:]]*\)*\n\(split[ab]\|splitba\)$/\n\2\n\n\1\n\3/ # 文字列後半の先頭が検索パターンに合うなら、文字列前半と後半だけを、改行ではさんで出力 :spltaf1 /\n\([[:print:]]*\)\n[[:print:]]*\n\1[[:print:]]*\nsplit\([ab]\|ba\)$/ { s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\1\([[:print:]]*\)\n\(splita\)$/\n\2\1\n\3/ s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\1\([[:print:]]*\)\n\(splitb\)$/\n\2\n\1\3/ s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\1\([[:print:]]*\)\n\(splitba\)$/\n\2\n\1\n\3/ bspltaf2 } # もしそうでないなくて、文字列後半に文字があるなら、 /\n[[:print:]]\{1,\}\nsplit\([ab]\|ba\)$/ { # 文字列後半の先頭一文字を文字列前半の最後に移動 s/\n\([[:print:]]*\)\n\([[:print:]]\)\([[:print:]]*\)\n\(split[ab]\|splitba\)$/\n\1\2\n\3\n\4/ # そのうえで、もう一度検査する bspltaf1 } :spltaf2 bout } # レベル2 の先頭から レベル1 の文字列を削除する /\ndecapstring$/ { s/\ndecapstring$// s/\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\1/ s/\n\([[:print:]]*\)\n\1\([[:print:]]*\)$/\n\1\n\2/ s/\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2/ bout } # レベル2 の末尾から レベル1 の文字列を削除する /\nchopstring$/ { s/\nchopstring$// s/\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\1/ s/\n\([[:print:]]*\)\n\([[:print:]]*\)\1$/\n\1\n\2/ s/\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2/ bout } # レベル2 中にレベル1 の内容が含まれていれば、最後のマッチ直後でレベル2を分割する /\nsplitalast$/{ s/\nsplitalast$// s/\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\1/ s/\n\([[:print:]]*\)\n\([[:print:]]*\)\1\([[:print:]]*\)$/\n\2\1\n\3/ bout } # レベル2 中にレベル1 の内容が含まれていれば、最後のマッチ直前でレベル2を分割する /\nsplitblast$/{ s/\nsplitblast$// s/\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\1/ s/\n\([[:print:]]*\)\n\([[:print:]]*\)\1\([[:print:]]*\)$/\n\2\n\1\3/ bout } # レベル2 中にレベル1 の内容が含まれていれば、最後のマッチの前後でレベル2を分割する /\nsplitbalast$/{ s/\nsplitbalast$// s/\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\1/ s/\n\([[:print:]]*\)\n\([[:print:]]*\)\1\([[:print:]]*\)$/\n\2\n\1\n\3/ bout } #2 つの階層をつなげる a b join → ab /\njoin$/ {s/\n\([[:print:]]*\)\n\([[:print:]]*\)\njoin$/\n\1\2/; bout} #任意のデリミタでつなげる a b c putbetween → a c b /\nputbetween$/ {s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\nputbetween$/\n\1\3\2/; bout} #囲む a b c bracket → bac # a1 a2 ... an b c brackets → b a1 a2 ... an c /\nbracket$/{s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\nbracket$/\n\2\1\3/; bout} /\nnbrackets$/{s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\nbrackets$/\n\1\n\3\n\2\nrollds/; bout} # スタックのレベルを数え、その数を積む。 /\ndepth$/ { s/\ndepth$// h s/.*\t// s/[[:print:]]//g /\n\{100,\}/ {s/\n\{100,\}/-1/; H; g; bout} s/\n\{90,90\}/90/; s/\n\{80,80\}/80/; s/\n\{70,70\}/70/; s/\n\{60,60\}/60/; s/\n\{50,50\}/50/; s/\n\{40,40\}/40/; s/\n\{30,30\}/30/; s/\n\{20,20\}/20/; s/\n\{10,10\}/10/; s/\([1-9]\)0\n\n\n\n\n\n\n\n\n/\19/ s/\([1-9]\)0\n\n\n\n\n\n\n\n/\18/ s/\([1-9]\)0\n\n\n\n\n\n\n/\17/ s/\([1-9]\)0\n\n\n\n\n\n/\16/ s/\([1-9]\)0\n\n\n\n\n/\15/ s/\([1-9]\)0\n\n\n\n/\14/ s/\([1-9]\)0\n\n\n/\13/ s/\([1-9]\)0\n\n/\12/ s/\([1-9]\)0\n/\11/ s/\n\n\n\n\n\n\n\n\n/9/ s/\n\n\n\n\n\n\n\n/8/ s/\n\n\n\n\n\n\n/7/ s/\n\n\n\n\n\n/6/ s/\n\n\n\n\n/5/ s/\n\n\n\n/4/ s/\n\n\n/3/ s/\n\n/2/ s/\n/1/ s/^$/0/ H g bout } # 文字数を数えてその個数を積む /\ncountchars$/ { s/\ncountchars$// h s/.*\n// s/.\{90,90\}/90\n/; s/.\{80,80\}/80\n/; s/.\{70,70\}/70\n/; s/.\{60,60\}/60\n/; s/.\{50,50\}/50\n/; s/.\{40,40\}/40\n/; s/.\{30,30\}/30\n/; s/.\{20,20\}/20\n/; s/^.\{10,10\}/10\n/; s/\([1-9]\)0\n........./\19\n/ s/\([1-9]\)0\n......../\18\n/ s/\([1-9]\)0\n......./\17\n/ s/\([1-9]\)0\n....../\16\n/ s/\([1-9]\)0\n...../\15\n/ s/\([1-9]\)0\n..../\14\n/ s/\([1-9]\)0\n.../\13\n/ s/\([1-9]\)0\n../\12\n/ s/\([1-9]\)0\n./\11\n/ s/^[[:print:]]\{9,9\}$/\n9/ s/^[[:print:]]\{8,8\}$/\n8/ s/^[[:print:]]\{7,7\}$/\n7/ s/^[[:print:]]\{6,6\}$/\n6/ s/^[[:print:]]\{5,5\}$/\n5/ s/^[[:print:]]\{4,4\}$/\n4/ s/^[[:print:]]\{3,3\}$/\n3/ s/^[[:print:]]\{2,2\}$/\n2/ s/^[[:print:]]\{1,1\}$/\n1/ s/^$/\n0/ s/[0-9]*0[0-9]0[0-9]*/\n100 or more/ s/\n// H g s/\n[[:print:]]*\n\([[:print:]]*\)$/\n\1/ bout } # 1 から 99 までの数から 1 を引く # 99 1sub → 98 /\n[1-9][0-9]\{0,1\}\n1sub$/ { s/\n1sub$// /0$/ { s/\n10$/\n9/;s/\n20$/\n19/;s/\n30$/\n29/;s/\n40$/\n39/;s/\n50$/\n49/; s/\n50$/\n49/;s/\n60$/\n59/;s/\n70$/\n69/;s/\n80$/\n79/;s/\n90$/\n89/; b onesub } s/\n\([1-9]\{0,1\}\)1$/\n\10/; s/\n\([1-9]\{0,1\}\)2$/\n\11/; s/\n\([1-9]\{0,1\}\)3$/\n\12/; s/\n\([1-9]\{0,1\}\)4$/\n\13/; s/\n\([1-9]\{0,1\}\)5$/\n\14/; s/\n\([1-9]\{0,1\}\)6$/\n\15/; s/\n\([1-9]\{0,1\}\)7$/\n\16/; s/\n\([1-9]\{0,1\}\)8$/\n\17/; s/\n\([1-9]\{0,1\}\)9$/\n\18/; :onesub bout } # 0 から 98 までの数に 1 を足す # 98 1 add → 99 /\n[1-9]\{0,1\}[0-9]\n1add$/ { s/\n1add$// /9$/ { s/\n9$/\n10/;s/\n19$/\n20/;s/\n29$/\n30/;s/\n39$/\n40/;s/\n49$/\n50/; s/\n59$/\n60/;s/\n69$/\n70/;s/\n79$/\n80/;s/\n89$/\n90/; b oneadd } s/\n\([1-9]\{0,1\}\)8$/\n\19/; s/\n\([1-9]\{0,1\}\)7$/\n\18/; s/\n\([1-9]\{0,1\}\)6$/\n\17/; s/\n\([1-9]\{0,1\}\)5$/\n\16/; s/\n\([1-9]\{0,1\}\)4$/\n\15/; s/\n\([1-9]\{0,1\}\)3$/\n\14/; s/\n\([1-9]\{0,1\}\)2$/\n\13/; s/\n\([1-9]\{0,1\}\)1$/\n\12/; s/\n\([1-9]\{0,1\}\)0$/\n\11/; :oneadd bout } # (レベル2 / レベル1) を越えない最大の整数 /\ndivby$/ { s/\ndivby$// s/9\([0-9]\)$/##########################################################################################\1/ s/8\([0-9]\)$/################################################################################\1/ s/7\([0-9]\)$/######################################################################\1/ s/6\([0-9]\)$/############################################################\1/ s/5\([0-9]\)$/##################################################\1/ s/4\([0-9]\)$/########################################\1/ s/3\([0-9]\)$/##############################\1/ s/2\([0-9]\)$/####################\1/ s/1\([0-9]\)$/##########\1/ s/\(#*\)9$/\1#########/ s/\(#*\)8$/\1########/ s/\(#*\)7$/\1#######/ s/\(#*\)6$/\1######/ s/\(#*\)5$/\1#####/ s/\(#*\)4$/\1####/ s/\(#*\)3$/\1###/ s/\(#*\)2$/\1##/ s/\(#*\)1$/\1#/ s/\(#*\)0$/\1/ s/\n\([[:digit:]]\{1,\}\)\n\(#\{1,\}\)$/\n\2\n\1/ s/9\([0-9]\)$/##########################################################################################\1/ s/8\([0-9]\)$/################################################################################\1/ s/7\([0-9]\)$/######################################################################\1/ s/6\([0-9]\)$/############################################################\1/ s/5\([0-9]\)$/##################################################\1/ s/4\([0-9]\)$/########################################\1/ s/3\([0-9]\)$/##############################\1/ s/2\([0-9]\)$/####################\1/ s/1\([0-9]\)$/##########\1/ s/\(#*\)9$/\1#########/ s/\(#*\)8$/\1########/ s/\(#*\)7$/\1#######/ s/\(#*\)6$/\1######/ s/\(#*\)5$/\1#####/ s/\(#*\)4$/\1####/ s/\(#*\)3$/\1###/ s/\(#*\)2$/\1##/ s/\(#*\)1$/\1#/ s/\(#*\)0$/\1/ s/$/\n/ :divby /\n\(##*\)\n\1\(#*\)\n\(#*\)$/ { s/\n\(##*\)\n\1\(#*\)\n\(#*\)$/\n\1\n\2\n\3#/ bdivby } s/\n#*\n#*\n\(#*\)$/\n\1/ #s/\n[[:print:]]*\n\([[:print:]]*\)$/\n\1/ h s/.*\n// s/.\{90,90\}/90\n/; s/.\{80,80\}/80\n/; s/.\{70,70\}/70\n/; s/.\{60,60\}/60\n/; s/.\{50,50\}/50\n/; s/.\{40,40\}/40\n/; s/.\{30,30\}/30\n/; s/.\{20,20\}/20\n/; s/^.\{10,10\}/10\n/; s/\([1-9]\)0\n........./\19\n/ s/\([1-9]\)0\n......../\18\n/ s/\([1-9]\)0\n......./\17\n/ s/\([1-9]\)0\n....../\16\n/ s/\([1-9]\)0\n...../\15\n/ s/\([1-9]\)0\n..../\14\n/ s/\([1-9]\)0\n.../\13\n/ s/\([1-9]\)0\n../\12\n/ s/\([1-9]\)0\n./\11\n/ s/\n[[:print:]]\{9,9\}$/\n9/ s/^[[:print:]]\{8,8\}$/\n8/ s/^[[:print:]]\{7,7\}$/\n7/ s/^[[:print:]]\{6,6\}$/\n6/ s/^[[:print:]]\{5,5\}$/\n5/ s/^[[:print:]]\{4,4\}$/\n4/ s/^[[:print:]]\{3,3\}$/\n3/ s/^[[:print:]]\{2,2\}$/\n2/ s/^[[:print:]]\{1,1\}$/\n1/ s/^$/\n0/ s/[0-9]*0[0-9]0[0-9]*/\n100 or more/ s/\n// H g s/\n[[:print:]]*\n\([[:print:]]*\)$/\n\1/ bout } # 文字単位の編集 # 最初の一文字を削除 abc decap → bc /\ndecap$/ { s/\ndecap$// s/\n[[:print:]]\([[:print:]]*\)$/\n\1/ bout } # 最後の一文字を削除 abc chop → ab /\nchop$/ { s/\nchop$// s/\n\([[:print:]]*\)[[:print:]]$/\n\1/ bout } /\n\(insert\|delete\|replace\)$/ { ## 挿入 abcde [SPACE][SPACE]@ XYZ insert → abXYZcde /\ninsert$/ { s/\n\([[:print:]]*\)\n\( *\)\(@\{1,\}\)\n\([[:print:]]*\)\ninsert$/\n\1\n\2\n\4\nreplace/ } ## 削除 abcde [SPACE][SPACE]@@ delete → abe #(対象となる部分文字列を空文字列と置き換える) /\ndelete$/ { s/\n\([[:print:]]*\)\n\( *@\{1,\}\)\ndelete$/\n\1\n\2\n\nreplace/ } ## 置き換え abcde [SPACE][SPACE]@@ xy replace → abxye /\n[[:print:]]*\n *@*\n[[:print:]]*\nreplace$/ { s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\nreplace$/\n\2\n\n\1\n\3/ :subst1 s/\n\( \)\( *@*\)\n\([[:print:]]*\)\n\([[:print:]]\)\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\3\4\n\5\n\6/; tsubst1 :subst2 s/\n\(@\)\(@*\)\n\([[:print:]]*\)\n\([[:print:]]\)\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\3\n\5\n\6/ tsubst2 s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\4\3/ } bout } ## 分離 abcde [SPACE][SPACE]@ split → ab cde /\n[[:print:]]*\n \{1,\}@\{1,\}\nsplit$/ { #「分離の仕方を示す文字列、頭から切離された文字列(最初は空)、残りの文字列(最初は対象文字列そのもの)」 # となるように並び換える s/\n\([[:print:]]*\)\n\([[:print:]]*\)\nsplit$/\n\2\n\n\1/ :splt #「分離の仕方を示す文字列」先頭一文字が[SPACE]ならばそれを削除したうえで、 # 「残り文字列」の最初の一文字を「頭から切離された文字列」に移す s/\n\( \)\( *@\{1,\}\)\n\([[:print:]]*\)\n\([[:print:]]\)\([[:print:]]*\)$/\n\2\n\3\4\n\5/; tsplt #元のように並び換える s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\3/ bout } ## 分離 abcde 2 splitn → ab cde /\n[[:print:]]*\n[1-9][0-9]*\nsplitn$/ { s/\nsplitn$// s/9\([0-9]\)$/##########################################################################################\1/ s/8\([0-9]\)$/################################################################################\1/ s/7\([0-9]\)$/######################################################################\1/ s/6\([0-9]\)$/############################################################\1/ s/5\([0-9]\)$/##################################################\1/ s/4\([0-9]\)$/########################################\1/ s/3\([0-9]\)$/##############################\1/ s/2\([0-9]\)$/####################\1/ s/1\([0-9]\)$/##########\1/ s/\(#*\)9$/\1#########/ s/\(#*\)8$/\1########/ s/\(#*\)7$/\1#######/ s/\(#*\)6$/\1######/ s/\(#*\)5$/\1#####/ s/\(#*\)4$/\1####/ s/\(#*\)3$/\1###/ s/\(#*\)2$/\1##/ s/\(#*\)1$/\1#/ s/\(#*\)0$/\1/ s/$/@/ #「分離の仕方を示す文字列、頭から切離された文字列(最初は空)、残りの文字列(最初は対象文字列そのもの)」 # となるように並び換える s/\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\n\1/ :spltn #「分離の仕方を示す文字列」先頭一文字が # ならばそれを削除したうえで、 # 「残り文字列」の最初の一文字を「頭から切離された文字列」に移す s/\n\(#\)\(#*@\{1,\}\)\n\([[:print:]]*\)\n\([[:print:]]\)\([[:print:]]*\)$/\n\2\n\3\4\n\5/; tspltn #元のように並び換える s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\3/ bout } ## 分離(後ろから) abcde [SPACE][SPACE]@ backsplit → abc de /\n[[:print:]]*\n \{1,\}@\{1,\}\nbacksplit$/ { #「分離の仕方を示す文字列、残りの文字列(最初は対象文字列そのもの)、尻から切離された文字列(最初は空)」 # となるように並び換える s/\n\([[:print:]]*\)\n\([[:print:]]*\)\nbacksplit$/\n\2\n\1\n/ :bsplt #「分離の仕方を示す文字列」先頭一文字が[SPACE]ならばそれを削除したうえで、 # 「残り文字列」から最後の一文字を「尻から切離された文字列」に移す s/\n\( \)\( *@\{1,\}\)\n\([[:print:]]*\)\([[:print:]]\)\n\([[:print:]]*\)$/\n\2\n\3\n\4\5/; tbsplt s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\3/ bout } ## 分離 abcde 2 backsplitn → ab cde /\n[[:print:]]*\n[1-9][0-9]*\nbacksplitn$/ { s/\nbacksplitn$// s/9\([0-9]\)$/##########################################################################################\1/ s/8\([0-9]\)$/################################################################################\1/ s/7\([0-9]\)$/######################################################################\1/ s/6\([0-9]\)$/############################################################\1/ s/5\([0-9]\)$/##################################################\1/ s/4\([0-9]\)$/########################################\1/ s/3\([0-9]\)$/##############################\1/ s/2\([0-9]\)$/####################\1/ s/1\([0-9]\)$/##########\1/ s/\(#*\)9$/\1#########/ s/\(#*\)8$/\1########/ s/\(#*\)7$/\1#######/ s/\(#*\)6$/\1######/ s/\(#*\)5$/\1#####/ s/\(#*\)4$/\1####/ s/\(#*\)3$/\1###/ s/\(#*\)2$/\1##/ s/\(#*\)1$/\1#/ s/\(#*\)0$/\1/ s/$/@/ #「分離の仕方を示す文字列、残りの文字列(最初は対象文字列そのもの)、尻から切離された文字列(最初は空)」 # となるように並び換える s/\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\1\n/ :bspltn #「分離の仕方を示す文字列」先頭一文字が # ならばそれを削除したうえで、 # 「残り文字列」から最後の一文字を「尻から切離された文字列」に移す s/\n\(#\)\(#*@\{1,\}\)\n\([[:print:]]*\)\([[:print:]]\)\n\([[:print:]]*\)$/\n\2\n\3\n\4\5/; tbspltn s/\n\([[:print:]]*\)\n\([[:print:]]*\)\n\([[:print:]]*\)$/\n\2\n\3/ bout } #スタック操作1(消去) ## 5 4 3 2 1 drop → 5 4 3 2 /\ndrop$/{s/\n[[:print:]]*\ndrop$//;bout} ## 5 4 3 2 1 clear /\nclear$/{s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)/\1\t\2\t\3\t\4\t/;bout} ## 5 4 3 2 1 nip → 1 /\nnip$/{s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t.*\(\n[[:print:]]*\)\nnip$/\1\t\2\t\3\t\4\t\5/;bout} #スタック操作2(複製) ## 5 4 3 2 1 dup → 5 4 3 2 1 1 /\ndup$/{s/\(\n[[:print:]]*\)\ndup$/\1\1/;bout} ## 5 4 3 2 1 dup2 → 5 4 3 2 1 2 1 /\ndup2$/{s/\(\n[[:print:]]*\)\(\n[[:print:]]*\)\ndup2$/\1\2\1\2/;bout} ## 5 4 3 2 1 over → 5 4 3 2 1 2 /\nover$/{s/\(\n[[:print:]]*\)\(\n[[:print:]]*\)\nover$/\1\2\1/;bout} ## 5 4 3 2 1 pick3 → 5 4 3 2 1 3 #/\npick3$/{s/\(\n[[:print:]]*\)\(\n[[:print:]]*\)\(\n[[:print:]]*\)\npick3$/\1\2\3\1/;bout} #スタック操作3(順序変更) ## 5 4 3 2 1 swap → 5 4 3 1 2 /\nswap$/ {/\nswap$/s/\(\n[[:print:]]*\)\(\n[[:print:]]*\)\nswap$/\2\1/; bout} ## 5 4 3 2 1 rolls → 4 3 2 1 5 # 1 2 3 4 5 6 # \t \t \t \t [\n ..]* \n /\nrolls$/ { /\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(\n[[:print:]]*\)\(\n.*\)\nrolls$/ { s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(\n[[:print:]]*\)\(\n.*\)\nrolls$/\1\t\2\t\3\t\4\t\6\5/ bout } s/\nrolls$// bout } ## 5 4 3 2 1 → rollsbut1 4 3 2 5 1 /\nrollsbut1$/{s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(\n[[:print:]]*\)\(\n.*\)\(\n[[:print:]]*\)\nrollsbut1$/\1\t\2\t\3\t\4\t\6\5\7/;bout} ## 5 4 3 2 1 → rollsbut2 4 3 5 2 1 /\nrollsbut2$/{s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(\n[[:print:]]*\)\(\n.*\)\(\n[[:print:]]*\)\(\n[[:print:]]*\)\nrollsbut2$/\1\t\2\t\3\t\4\t\6\5\7\8/;bout} # 5 4 3 2 1 → rolldsbut1 2 5 4 3 1 /\nrolldsbut1$/{s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(\n.*\)\(\n[[:print:]]*\)\(\n[[:print:]]*\)\nrolldsbut1$/\1\t\2\t\3\t\4\t\6\5\7/;bout} # 5 4 3 2 1 → rolldsbut2 3 5 4 2 1 /\nrolldsbut2$/{s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(\n.*\)\(\n[[:print:]]*\)\(\n[[:print:]]*\)\(\n[[:print:]]*\)\nrolldsbut2$/\1\t\2\t\3\t\4\t\6\5\7\8/;bout} ## 5 4 3 2 1 3roll → 5 4 2 1 3 (this command is deleted) #/\n3roll$/{s/\(\n[[:print:]]*\)\(\n[[:print:]]*\)\(\n[[:print:]]*\)\n3roll$/\2\3\1/;bout} ## 5 4 3 2 1 rollds → 1 5 4 3 2 /\nrollds$/{ /\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(\n.*\)\(\n[[:print:]]*\)\nrollds$/ { s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(\n.*\)\(\n[[:print:]]*\)\nrollds$/\1\t\2\t\3\t\4\t\6\5/ bout } s/\nrollds$// bout } ## 5 4 3 2 1 3rolld → 5 4 1 3 2 /\n3rolld$/{s/\(\n[[:print:]]*\)\(\n[[:print:]]*\)\(\n[[:print:]]*\)\n3rolld$/\3\1\2/;bout} ## 5 4 3 2 1 3 dupn → 5 4 3 2 1 3 2 1 # この時点で、...\n数字\nコマンド名 になっている /\n[[:digit:]]\{1,2\}\n\(dupn\|pick\|unpick\|roll\|rolld\)$/ { /\n1\nroll$/ { s/\n1\nroll$//; bout} # 1 roll の場合 /\n1\nrolld$/ { s/\n1\nrolld$//; bout} # 1 rolld の場合 # コマンドをホールドスペースに保存 h s/.*\n\([[:print:]]*\)$/\1/ x # コマンド保存おわり # コマンド名削除 s/\n[[:print:]]*$// # ...\n数字 を ...\n##...# に置換 s/9\([0-9]\)$/##########################################################################################\1/ s/8\([0-9]\)$/################################################################################\1/ s/7\([0-9]\)$/######################################################################\1/ s/6\([0-9]\)$/############################################################\1/ s/5\([0-9]\)$/##################################################\1/ s/4\([0-9]\)$/########################################\1/ s/3\([0-9]\)$/##############################\1/ s/2\([0-9]\)$/####################\1/ s/1\([0-9]\)$/##########\1/ s/\(#*\)9$/\1#########/ s/\(#*\)8$/\1########/ s/\(#*\)7$/\1#######/ s/\(#*\)6$/\1######/ s/\(#*\)5$/\1#####/ s/\(#*\)4$/\1####/ s/\(#*\)3$/\1###/ s/\(#*\)2$/\1##/ s/\(#*\)1$/\1#/ s/\(#*\)0$/\1/ # 作業用のスペースとして、...\n##...# の後に\tをつけ ...\n##...#\t(作業用スペース) とする s/$/\t/ :dupn # "#"が 1 つ以上残っていて、スタックに 1 つ以上のレベルがあればマッチする /.*\t.*\t.*\t.*\t.*\n.*\n##*\t.*/{ # レベル1 を作業用スペースに移動する # 1 2 3 4 5 6 7 8 # M? cmds rec1 rec2 ... level(1) ##... # copied # \t \t \t \t \n \n \t s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\(\n[[:print:]]*\)\n\(#*\)#\t\(.*\)$/\1\t\2\t\3\t\4\t\5\n\7\t\6\8/ bdupn } # ここに至るのは、"#" が尽きるか、スタック中のレベルが尽きるかしたときである。 # "#" が残っているのにスタック中のレベルが尽きたならば、元の状態に復帰して終了 /.*\t.*\t.*\t.*\t\n##*\t.*/ { s/\(.*\t.*\t.*\t.*\t\)\n##*\t\(.*\)/\1\2/ bout } x # コマンドを取り出す /^dupn$/{ x s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\n\t\(.*\)/\1\t\2\t\3\t\4\t\5\6\6/; bout } /^pick$/{ x # 1 2 3 4 5 6 s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\n\t\n\([[:print:]]*\)\(.*\)/\1\t\2\t\3\t\4\t\5\n\6\7\n\6/ ;bout} /^unpick$/{ x /.*\t.*\t.*\t.*\t\n\t/ { s/\(.*\t.*\t.*\t.*\t\)\n\t\(.*\)/\1\2/ #s/$/*/ #debug bout } # ... Aの末尾 旧# B Bの末尾 # 1 2 3 4 5 6 7 8 s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\n\([[:print:]]*\)\n\t\n\(.*\)\n\([[:print:]]*\)$/\1\t\2\t\3\t\4\t\5\n\8\n\7/ ;bout} /^roll$/{ x # ( A ) # ( | B ) # 1 2 3 4 5 6 7 s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\n\t\n\([[:print:]]*\)\n\(.*\)$/\1\t\2\t\3\t\4\t\5\n\7\n\6/; bout } /^rolld$/{ x # ( A ) # ( | B | ) # 1 2 3 4 5 6 7 8 s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\n\t\([[:print:]]*\)\n\(.*\)\n\([[:print:]]*\)$/\1\t\2\t\3\t\4\t\5\n\8\n\7/; bout } x bout } #入力が空行なら無視する s/\n$// #undo で一つ前のスタックの状態に戻る。undo undo は元に戻る。 /\nundo$/ s/^\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\nundo$/\1\t\2\t\3\t\4\t\3/ #文字通りにスタックに積む "a" → a # "a → a /\n"[[:print:]]*"$/ { s/\n"\([[:print:]]*\)"$/\n\1/ bout } /\n"[[:print:]]*$/ { s/\n"\([[:print:]]*\)$/\n\1/ bout } #:a # print で、現在のスタックの内容を標準出力に出力する(sed が -n オプションつきで実行されている場合に有用) /\nprint$/ { h s/^\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)$/\5/ s/\nprint$// p g s/^\(.*\)\t\(.*\)\t\(.*\)$/\1\t\1\t\2/; } # write で、現在のスタックの内容を rpnedit.tmp に追加する。 # この追加後に、"[END_OF_STACK]" という文字列を追加する。 # なお、rpnedit.tmp ファイルは、sed 起動時に空にされる(これは sed の仕様)。 /\nwrite$/ { s/\nwrite$// h s/^\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)$/\5/ s/^\n// s/$/\n[END_OF_STACK]/ w rpnedit.tmp g /^M/! { #マクロの中から呼び出された場合でないなら、履歴を 1 回ぶん戻す s/^\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)$/\1\t\2\t\3\t\3\t\4/; } } # write と同様だが、rpnedit.tmp1 に書き出す /\nwrite1$/ { s/\nwrite1$// h s/^\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)$/\5/ s/^\n// s/$/\n[END_OF_STACK]/ w rpnedit.tmp1 g /^M/! { #マクロの中から呼び出された場合でないなら、履歴を 1 回ぶん戻す s/^\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)$/\1\t\2\t\3\t\3\t\4/; } } :out # (\tで区切られた2番目のセルに、実行すべき命令(マクロによって積まれたもの)が残っているなら、 # それらのうち最初にある 1 命令を最後のセルに積んだうえでループに入る。このとき、最初のセルに # M をセットしてマクロ実行中である印とする) # /.*\t\n.*\t.*\t.*\t.*/ { #s/\(.*\)\n\(.*\)\t\(\n[[:print:]]*\)\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)/M\n\2\t\4\t\5\t\6\t\7\3/ h s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)/\2/ # パターンスペースをコマンドキューだけにする s/|||/\n/g # すべての ||| を \n に置換 s/^/\t/ # 目印に \t をつける H # ホールドスペースの末尾にこれを追加し # (一時的に \t が 5 個あることになる) g # パターンスペースにコピーする s/\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\n\t\(.*\)/\1\t\6\t\3\t\4\t\5/ # コマンドキューを書き換える # (ここで \t は 4 個の正常な状態に戻る) # あとはコマンドキューから命令を1つ現在のスタックにプッシュする s/\(.*\)\n\(.*\)\t\(\n[[:print:]]*\)\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)/M\n\2\t\4\t\5\t\6\t\7\3/ # ^^^^^^^^^^^^^^ ^^ # これが この 前にあるということは、意味深いことである。 # コマンドキューは新しいものが末尾に積まれて、先頭のほうからとり出されるのである。 b domacro } #マクロ実行中のマークがあるなら削除する(ここはマクロのためのループの外ゆゑ) s/^M\n/\n/ # /\nquit$/ { s/.*// a\ Bye!\ Press [Enter]. q } #(作業中のスタックの内容を(undo のために)記録) s/^\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)\t\(.*\)$/\1\t\2\t\4\t\5\t\5/; h # debug #s/\t/\t|/g #s/\n/*/g #p #b #s/\t/\t|/g #debug #s/\n/@/g #debug #b #debug # (出力用に、\t で区切られた最後の部分、つまり、現在のスタックだけを残してそれ以前を削除) s/.*\t// # 最初に \t 最後に \t\t を付加して、デリミタとする s/^/\t/ s/$/\t\t/