2001/7/16


情報処理2001・藤村逸子の宿題

情報処理の授業ホーム


パールのうた:

プログラム動くときだけうれしくて,動かなければ頭まっしろ

lapin


目次: 
1.苦労した点
2.語彙頻度表
3.1文の平均語数
4.もっとも長い文
5.perlの入門の入門6/1
6.入門2(やれやれ・・・)
7.入門3(情報処理道4級ぐらいはもらえるかなぁ)
8.入門4(終わりが近い!やっぱりむずかしい...)
9・入門5(問題Aはできるんだけど..)
10.入門6(この間の質問のおかげて快調になってきた!!)


<1>,<2>で苦労した点:

初心者向けの授業だから,文中の改行は,あらかじめきっと,とってあるだろうと思っていたが,その思いこみがあだとなった.また,改行の取り方について,授業中にちゃんと教えてもらった覚えがないということも,意外であった.しかし,もっとも苦労したのは,sedが普通に使えず,/mdhome/pub/sparc/bin/sed をつかわなければならないという点であった.

初心者向けの授業の常識を大きく逸脱しており,常識的には,ありえない宿題だと思われた.しかし,手が届きそうで届かないような課題を設定することは,その分野の学習に意欲的な学習者にとってはなかなか効果的な方法だということがよく分かりました.教師のやり方の勉強もさせていただきました. > 杉浦先生


<1>「あしながおじさん」の語彙頻度表

lfujimura0@sv007% less kaigyo.sed
s/ /\
/g


lfujimura0@sv006% tr '\n' ' ' < longlegor.txt | tr '\r' ' '|/mdhome/pub/sparc/bin/sed "s/['\.\)\(,!\?:;-]/ /g" |
/mdhome/pub/sparc/bin/sed 's/"/ /g' | /mdhome/pub/sparc/bin/sed 's/`/ /g' |/mdhome/pub/sparc/bin/sed 's/ */ /g' | /mdhome/pub/sparc/bin/sed -f kaigyo.sed | grep -v '^ *$' | sort -f | uniq -c > longwords1.txt

改行をとったあと,アルファベット以外の全ての記号を削除.空白が重複しないように調整.念のために空行がないかチェック.あとは,空白で改行し,行頭の空白をとり,ソートする.

lfujimura0@sv006% sort -k 2 -f longwords1.txt | more
38 A
995 a
1 ab
2 Ab
3 abandoned
1 Abbey

39 Abbott
2 ability
1 Ablative
1 ablative
11 able
1 abolished
108 about
1 above
3 abroad
1 absence
1 Absolute
1 absolute
5 absolutely
2 absorbing
1 absorption
1 absque
1 abstract
1 abstruse
1 absurd
1 abuse
1 abusive
1 abyss
1 academic
2 accent
9 accept



lfujimura0@sv007% sort -n -r longwords1.txt | awk '{ print $2, $1 }' | more
I 1605
the 1419
and 1315
to 1085
a 995
of 670
you 644
in 560
t 467
that 441
it 407
is 333
s 320
with 300
for 293
was 255
me 249
have 243
be 242
my 240
but 222
he 204
are 192
Daddy 188
at 175
It 169
as 165
on 160
so 158
had 157
all 154
m 149
we 148
very 143
an 142
am 141
The 135
not 132
this 129
up 128
can 124
your 121
ve 120
from 120
know 117--
don 117
just 112
think 111
one 109
about 108
when 106
she 103
they 102
You 102
or 100
going 100


<2>「あしながおじさん」の1文あたり平均語数

lfujimura0@sv007% less kaigyo1.sed

s/Mr\./MR/g
s/Mrs\./MRS/g
s/am\./AM/g
s/pm\./PM/g
s/\./.\
/g
s/?/?\
/g
s/!./!\
/g
s/MR/Mr./g
s/MRS/Mrs./g
s/AM/am./g
s/PM/pm./g

lfujimura0@sv007% tr '\n' ' ' < longlegor.txt | tr '\r' ' ' | /mdhome/pub/sparc/
bin/sed -f kaigyo1.sed | /mdhome/pub/sparc/bin/sed "s/^ *'//g" | /mdhome/pub/spa
rc/bin/sed 's/^ *//g' | sed 's/ */ /g' > longsen.txt

ここまでで,1文1行になった.

lfujimura0@sv006% sort -f longlegsen.txt | awk '{ print NF, $0 }' | awk -f heikin.awk
HEIKIN:37101

総単語数がでた.

lfujimura0@sv007% less heikin.awk
{heikin = heikin + $1 }
END { print "HEIKIN:" heikin }

lfujimura0@sv006% awk 'END { print NR, $0}' longlegsen.txt
2603 Isn't it funny that I know how

総行数がでた.

lfujimura0@sv006% bc -l
37101/2603
14.25316941990011525163

わり算!



<おまけ:1番長い文はこの2文>

しかし,二つ目の文は,コロンのあとが大文字なので,全体が一文とは言えないでしょうね.この辺から先は,手作業の方が効率的かな?

lfujimura0@sv007% awk '{print NF, $0}' longsen.txt | sort -n | tail

88 I meant to have written a lot about the budding trees and the new cinder path in the athletic field, and the awful lesson we have in biology for tomorrow, and the new canoes on the lake, and Catherine Prentiss who has pneumonia, and Prexy's Angora kitten that strayed from home and has been boarding in Fergussen Hall for two weeks until a chambermaid reported it, and about my three new dresses-- white and pink and blue polka dots with a hat to match--but I am too sleepy.

88 I don't think I am telling you at all what I started to say, which was this: Although my feelings are still hurt, for it is very humiliating to be picked up and moved about by an arbitrary, peremptory, unreasonable, omnipotent, invisible
Providence, still, when a man has been as kind and generous and thoughtful as you have heretofore been towards me, I suppose he has a right to be an arbitrary, peremptory, unreasonable, invisible Providence if he chooses, and so-- I'll for give you and be cheerful again.


<6月1日の宿題:perlの入門の入門>

練習問題A:

1.longleg.txt の各行の先頭に行番号を付けて出力するスクリプト:

% perl -ne 'print "$.\t$_";' longleg.txt

間にタブを入れた.

2.longleg.txt から 'Pendleton' を含む行を,行番号を付けて出力するスクリプト:

% perl -ne 'if(m/Pendleton/){print "$. $_";}' longleg.txt

行番号付きgrepと同じ.

3.上のスクリプトに手を加え,'Pendleton' にマーキングして出力するようにしなさい。マーキングは '<<Pendleton>>' などのようにする。

% perl -ne 'if(m/Pendleton/){s/Pendleton/<<Pendleton>>/g; print "$. $_";}' longleg.txt

どこにあるかわかってとてもいい!

練習問題B:

1.longleg.txt から 'Pendleton' を含む行を以下の形式で出力するスクリプト:
a) 各行の先頭には,通し番号と行番号を付ける。
b) 'Pendleton' にはマーキングする。

% perl -ne 'if(m/Pendleton/){s/Pendleton/**Pendleton**/g; $count = $count + 1; print "$count $. $_";}' longleg.txt

いくつあるかもわかる!

2.longleg.txt の空行以外の各行の先頭に行番号を付けて出力するスクリプト:

% perl -ne 'if(m/^[^\n]+$/){print "$. $_";}' longleg.txt

3.longleg.txt の各段落(空行で区切られた行の集まり)の改行を取るスクリプト:

% perl -pe 'if(m/^[^\n]+$/){s/\n/ /g;}' longleg.txt

/^[^\n]+$/は,改行以外の文字を一つ以上含む行.

デフォルトは行を単位とするので,^$(行)を考えに入れる必要はない.マッチングは,行を指定しているのであって,文字列を指定しているわけではないから.

/^[^\n]+$/は不必要に詳しい./[^\n]/ に変えましょう.(あるいは,/./でさえもよい..は改行を含まないから.)

オプションの-peはlongleg.txt全体を自動的に出力する.-neだと自動的な出力はない.また,あとに print;をつけて出力しても,ifで指定したレコードのみを出力するため,段落の区切りが見えなくなり,この課題の場合には実用的でない.


<6月15日の宿題,やれやれ!むずかしいなぁ..>

練習問題A:

1.ディレクトリ voa にあるファイルから,日本関連の記事を抜きだしなさい。記事にファイル名を付ける,連番を振る,キーワードをマークするなど,出力の仕方を工夫すること。

% perl -e '$/ = indef; while (<>) {if (/japan[a-z]*/ig) {s/$&/<<
$&>>/; $count++; print "******$count**********\n$ARGV\n$_\n"}}' voa/*

2.5月18日の課題として作成した語彙頻度一覧表の上位5語について,Perl を使って出現回数を調べなさい。出現回数が異なるもの
については,その理由について考えなさい。

% perl -ne 'while ( /\bI\b/g ) {$count++} END {print "I:$count\n
" ; }' longleg.txt
I:1605
% perl -ne 'while ( /\bthe\b/g ) {$count++} END {print "the:$count\n" ; }' longleg.txt
the:1419
% perl -ne 'while ( /\band\b/g ) {$count++} END {print "and:$count\n" ; }' longleg.txt
and:1315

% perl -ne 'while ( /\bto\b/g ) {$count++} END {print "to:$count\n" ; }' longleg.txt
to:1085

% perl -ne 'while ( /\ba\b/g ) {$count++} END {print "a:$count\n
" ; }' longleg.txt
a:995

上を見るとわかるように,出現回数はぴったりまったく同じでした.もし違うとすれば何が違うのだろうか?

whileの変わりにifを使ってみると,出現回数は少なくなった.たとえばこれ.

% perl -ne 'if( /\bI\b/g ) {$count++} END {print "I:$count\n" ; }' longleg.txt
I:1238

ifはレコードをずぅっと調べてみて最後までたどり着くと終しまい,whileは条件が満たされている限り何度でも調べる.つまり,ifは,同一レコードにあるものは2つあっても1回しか数えないが,whileは,あるだけ,ちゃんと数える.


練習問題B:余裕があったらやってみよう。

1.data/aesop.txt から,「うさぎと亀」の話を抜きだしなさい。

ヒント1:話と話の間に空行2つが入っていることに着目する。

ヒント2: 「うさぎに当たる英単語 (rabbit, hare)」と「亀に当たる英単語 (tortoise, turtle)」が両方出現しているデータを抜き出す
には,次の2つの方法が考えられる。

a.一方を含むものを抜き出し,それを対象にもう一方が含まれているものを抜き出す。

lfujimura0@sv006% perl -e '$/ = "\n\n\n"; while (<>) {if (/(tortoise|turtle)/ig)
{ s/$&/<<$&>>/g; print;}}' lapin.txt

****2****
The <<Hare>> and the <<Tortoise>>

A HARE one day ridiculed the short feet and slow pace of the
<<Tortoise>>, who replied, laughing: "Though you be swift as the
wind, I will beat you in a race." The <<Hare>>, believing her
assertion to be simply impossible, assented to the proposal; and
they agreed that the Fox should choose the course and fix the
goal. On the day appointed for the race the two started
together. The <<Tortoise>> never for a moment stopped, but went on
with a slow but steady pace straight to the end of the course.
The <<Hare>>, lying down by the wayside, fell fast asleep. At last
waking up, and moving as fast as he could, he saw the <<Tortoise>>
had reached the goal, and was comfortably dozing after her
fatigue.

Slow but steady wins the race.

b.両方が含まれていることを条件として指定して抜き出す。[and, && について]

% perl -e '$/ = "\n\n\n"; while (<>) {if (/(rabbit|hare)/ig and
/(tortoise|turtle)/ig ) { s/$&/<<$&>>/g; $count++; print "****$count******\n$_\n
";}}' data/aesop.txt
****1******
The Hare and the <<Tortoise>>

A HARE one day ridiculed the short feet and slow pace of the
<<Tortoise>>, who replied, laughing: "Though you be swift as the
wind, I will beat you in a race." The Hare, believing her
assertion to be simply impossible, assented to the proposal; and
they agreed that the Fox should choose the course and fix the
goal. On the day appointed for the race the two started
together. The <<Tortoise>> never for a moment stopped, but went on
with a slow but steady pace straight to the end of the course.
The Hare, lying down by the wayside, fell fast asleep. At last
waking up, and moving as fast as he could, he saw the <<Tortoise>>
had reached the goal, and was comfortably dozing after her
fatigue.

Slow but steady wins the race.

2.ll2ss.pl を longleg.txt 以外のテキストを対象に実行し,問題のある箇所をチェックしなさい。できるだけ問題が出ないようにスク
リプトに改良しなさい。


Perl 入門 3: 文字列の加工

4.出力の書式も変数で指定し,値を冒頭で指定するように ezkwic1.pl を書き換えなさい。

lfujimura0@sv007% more ezkwicpf.pl
#検索文字列の指定
$string = '\b(man|men|woman|women)\b';
#前の文脈の最後の文字数の指定
$left = '50';
#後の文脈の文字数の指定
$right = '10';

#「段落」単位で処理するため RS を空行に
$/ = "";

while(<>){

s/ *\n */ /g; #行の連結

while(/$string/ig){ #$string の内容は上で指定

$count++; #連番を振るため,数を数える

$key = $&; #$key にマッチした文字列を代入
$post = $'; #$post に後ろの文脈を代入
$pre = substr ($`, -$left); #前の文脈の文字数を代入
$file = $ARGV; #現在のファイル名を $file に代入
$file =~ s#.*/([^/]+)$#$1#; #パスが付いていたら削除

#書式を指定して出力
printf "%5d | %-12.12s | %${left}s|%s|%-${right}.${right}s\n",
$count, $file, $pre, $key, $post;

}
}
exit;

lfujimura0@sv007% perl ezkwicpf.pl voa/* | sort -f -t "|" -k 5 -r > voaman.txt
lfujimura0@sv007% more voaman.txt
26 | 2-257818 | and productivity. We are producing much more per |man|. So that
12 | 2-257755 | r after take-off, the flight was hijacked by five |men|. Mr. War
5 | 2-257729 | eved in the ruling party," says this 75-year- old |woman|. But she
16 | 2-257764 | spected in the party, and popular with Republican |women|.

余裕があったらやる問題:

1. この問題が一番手こずった.この下にある[3]のプログラムを全て終えた後で,$stringの直前の語の前に,"|"を挿入し,その後で,ソートするという方法:

% perl -ne

'if (s/(\S+) \|(man|men|woman|women)\|/|$1 |$2|/ig) {print;}' essai.txt | sort -f -t "|" -k 4 > essaisorted.txt

これを一つのスクリプトの中に入れることはできないのだろうか?この辺がよくわかりません.

結果は次のとおり:

% more essaisorted.txt
59 | longleg.txt | you is by turning out a Very Useful Citizen |(Are |women | citizens?
19 | longleg.txt | sation.**This is Sunday afternoon.**Amasai |(hired |man|) in a pur
13 | longleg.txt | **That's a great experience. I never talked to |a |man|
before (e
8 | longleg.txt | ining? He used to saunter out and casually kill |a |man|
before br
64 | longleg.txt | rd-- nobody would be to blame for anything. If |a |man|
believed
51 | longleg.txt | fully nice man with red hair--and Julia invited |a |man|
from New
36 | longleg.txt | , omnipotent, invisible Providence, still, when |a |man|
has been

2.全語のコンコーダンスはできた:

#検索文字列の指定
$string = '\b\S+\b';
#前の文脈の最後の文字数の指定
$left = '25';
#後の文脈の文字数の指定
$right = '25';

#「段落」単位で処理するため RS を空行に
$/ = "";

while(<>){

s/ *\n */ /g; #行の連結

while(/$string/ig){ #$string の内容は上で指定

$count++; #連番を振るため,数を数える

$key = $&; #$key にマッチした文字列を代入
$post = $'; #$post に後ろの文脈を代入
$pre = substr ($`, -$left); #前の文脈の文字数を代入
$file = $ARGV; #現在のファイル名を $file に代入
$file =~ s#.*/([^/]+)$#$1#; #パスが付いていたら削除

#書式を指定して出力
printf "%5d | %-12.12s | %${left}s|%-12.12s|%-${right}.${right}s\n",
$count, $file, $pre, $key, $post;

}
}
exit;

3. パラグラフを越えて文脈を表示させる

lfujimura0@sv007% more ezkwicpf3.pl
#検索文字列の指定
$string = '\b(man|men|woman|women)\b';
#前の文脈の最後の文字数の指定
$left = '50';
#後の文脈の文字数の指定
$right = '10';

#ファイル単位をレコードとする
$/ = undef;

while(<>){
s/\n\n/>><</g; #パラグラフの境界を>><<で表示

s/ *\n */ /g; #行の連結

while(/$string/ig){ #$string の内容は上で指定

$count++; #連番を振るため,数を数える

$key = $&; #$key にマッチした文字列を代入
$post = $'; #$post に後ろの文脈を代入
$pre = substr ($`, -$left); #前の文脈の文字数を代入
$file = $ARGV; #現在のファイル名を $file に代入
$file =~ s#.*/([^/]+)$#$1#; #パスが付いていたら削除

#書式を指定して出力
printf "%5d | %-12.12s | %${left}s|%s|%-${right}.${right}s\n",
$count, $file, $pre, $key, $post;

}
}
exit;


Perl入門4:ファイルへの入出力

練習問題A:

print STDERR "SERCH STRING: ": #ディスプレーにSERCH STRING: と表示する(厳密にいうとエラーとして表示)

$string = <STDIN>; #キーボードからの入力を$stringに代入する

chomp $string; #入力された文字列に区切り文字(改行)があるときには,それを削除し,削除した結果を$stringにかえす

2.左右の文字の長さもコマンドラインで指定する方法(前の宿題のA-4ができないと,これはできない):

ezkwic2_1.pl

...............

print STDERR "SEARCH STRING: ";
$string = <STDIN>;
chomp $string;

print STDERR "left length: ";
$left = <STDIN>;
chomp $left;

print STDERR "right length: ";
$right = <STDIN>;
chomp $right;

$/ = "";
while(<>){
s/ *\n */ /g;
while(/$string/ig){
$count++;
$key = $&;
$post = $';
$pre = substr ($`, -$left);
$file = $ARGV;
$file =~ s#.*/([^/]+)$#$1#;
printf "%5d | %-12.12s | %${left}s|%s|%-${right}.${right}s\n",
$count, $file, $pre, $key, $post;
}
}
exit;

% perl plscript/ezkwic2_1.pl longleg.txt
SEARCH STRING: sombre
left length: 40
right length: 15
1 | longleg.txt | wait in the drawing-room. It was a very |sombre|, magnifi
cent,


9.入門5,リスト,配列,for, foreach

A:

1.コマンドラインから処理するファイルを指定できるように merge.pl を書き換えなさい。(merge.pl
は前回扱ったスクリプト。)

2.下に示す txt2html.pl は,コマンドラインで指定した拡張子 .txt のファイルを全て HTML 文書化
するスクリプトである。スクリプトの内容を確認しなさい。

A-1

lfujimura0@sv007% more mergeav.pl
print "Type files to merge:"; #合体させるファイルを指定する
$string = <STDIN>;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
$string =~lc $string;
@ARGV = split ( /\s+/, $string);  #整形後そのファイルを@ARGVに代入

$fileA = $ARGV[0];
$fileB = $ARGV[1];

#ここから先は変更なし

open (INA, $fileA) or die;
open (INB, $fileB) or die;

while ($textA = <INA> and $textB = <INB>) {

if ($textA eq $textB) {
$textA =~ s/^(\*|\@End)/\n$&/;
print $textA;
} else {
chomp $textA; print "$textA ($fileA)\n";
chomp $textB; print "$textB ($fileB)\n";
}

}

exit;

A-2

動かしてみて知りたかったのは,htmlのタグがファイルにつき1カ所だけつくのかどうかということ.スクリプトでは,undef $/;と指定されているので,$_は,ファイルということになる.ファイル全体に一つのタグがつく結果になると推定し,それが確かめられた.

次に,上のA-1と合体させて,変換するファイルをコマンドラインで指定できるようにした.(たったこれだけのことに,とても時間がかかった.その理由はスクリプトを書くのが難しかったのではなく,どこかに紛れ込んでいたと思われる全角のスペースが原因である.この問題はこれまでにも何度も起きた.プログラムは,動くか動かないかのどちらかなので,どんな些細なミスもどんな大きなミスも結果にほとんど差がない.絶対に間違っているはずがないと思うのに,動かないとき,絶望的な気分になる.

plscript/txt2htmlessai.pl

...........................
print "Type files:"; #htmlに変換するファイルを指定する
$string = <STDIN>;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
$string =~lc $string;
@ARGV = split ( /\s+/, $string); #整形後そのファイルを@ARGVに代入

undef $/;

foreach $infile (@ARGV) {

#拡張子が .txt でなければ処理しない
next if ($infile !~ m/\.txt$/);

#出力ファイル名の指定
$outfile = $infile;
$outfile =~ s/txt$/html/;

#入力・出力ファイルを開く
open (IN, $infile);
open (OUT, ">$outfile");

#ファイルの中身を読み込む
$_ = <>;

#前後にタグを付けて出力
print OUT "<html>\n<body>\n<pre>\n";
print OUT $_;
print OUT "\n</pre>\n</body>\n</html>\n";

#ファイルを閉じる
close IN;
close OUT;

}

exit;


10.Perl入門6

練習問題A:

1.sort1.pl を参考にして,英文テキストに現れる単語を次の順番で並べ替えるスクリプトを書きなさ
い。

a.大文字小文字を区別せずにアルファベット順でソート

b.a. の逆順 (Z/z → A/a) でソート

c.単語を語尾から比較し,アルファベット順でソート
(-a で終わる単語が -b で終わる単語よりも先に来る。)

d.各単語の文字数でソート

2.longleg.txt に含まれる文を,文字数の大きいものから小さいものへと並べ替えなさい。以前作成
した1行1文に整形したテキストを利用すること。

3.適当なファイルを対象に sort2.pl と wordfreq.pl を実行しなさい。出力結果を確認し,なぜそう
なるのか,スクリプトの内容を確認しなさい。

1.a:sort1_1.pl

while (<>) {
push (@words, split);
}

foreach $i (sort {lc $a cmp lc $b } @words) {
print $i . "\n";
}

exit;

1.b:sort1_2.pl

foreach $i (sort {lc $b cmp lc $a } @words) {

1.c:sort1_3.pl

foreach $i (sort {lc (reverse $a) cmp lc (reverse $b) } @words) {

1.d:sort1_4.pl

foreach $i (sort {length $a <=> length $b } @words) {

2.
sort1_5.pl

while (<>) {
push (@lines, split(/\n+/, $_));
}

foreach $i (sort { length $a <=> length $b } @lines) {
print $i . "\n";
}

exit;

........................................................................................

これらが一番長い文です.ずっと前に同じことをしましたが,2番目のはぴったり一緒.1番目はなぜか違う.いずれにせよ,Perlのスクリプトの簡潔さに感動します.とてもエレガント.

This isn't much of a letter; I meant to have written a lot--but I've been hemming four window curtains and three portieres (I'm glad you can't see the length of the stitches), and polishing a brass desk set with tooth powder (very uphill work), and sawing off picture wire with manicure scissors, and unpacking four boxes of books, and putting away two trunkfuls of clothes (it doesn't seem believable that Jerusha Abbott owns two trunks full of clothes, but she does!) and welcoming back fifty dear friends in between.--

I meant to have written a lot about the budding trees and the new cinder path in the athletic field, and the awful lesson we have in biology for tomorrow, and the new canoes on the lake, and Catherine Prentiss who has pneumonia, and Prexy's Angora kitten that strayed from home and has been boarding in Fergussen Hall for two weeks until a chambermaid reported it, and about my three new dresses-- white and pink and blue polka dots with a hat to match--but I am too sleepy.

B.

1.

wordfreq_1.pl

#大文字と小文字について,頻度の計算は別々に行うが,並べ方としては一般の辞書のように同じ語あつかいで並べる.つまり,同じアルファベット同士では,大文字優先にするというスクリプト:lc $a cmp lc $b || $a cmp $b(これは私が考えついたのではなく,大名先生のページをよく探すと書いてあった.

while (<>) {push (@words, split);}
foreach $i (sort { lc $a cmp lc $b || $a cmp $b } @words) {
if ($i eq $prev) { #$iが前の単語と同じなら,


$count++; #カウンターの値を一つ大きくする。


} else { #違う単語なら,


print "$count\t$prev\n"; #「頻度+タブ+単語」の形式で出力,


$prev = $i; #新しい単語を$prevの値とし,


$count = 1; #カウンターを1に戻す。


}


}
print "$count\t$prev\n"; #最後の単語と頻度を出力
exit;

2.一行目の空行をとる:

配列の最初の語を配列から取り出して,$prevに代入しておく.こうすることによって,空の$prevということがなくなる.

.............................

この間,メーリングリストで質問してわかったことがとても役に立った.(ただし,この問題も私一人で解いたのではない.いろいろさがしていると,ヒント(というよりは,むしろ答えそのもの)がplscriptの中にすでにあった.

$prev = shift @sorted;

#配列:@sortedから,先頭の語を取り出し,$prevに代入する.同時に,@sortedは先頭の語を失う.結局

$prev + @sortedの値の集合は,もとの@sortedの値の集合と同じである.

.............................

wordfreq_3.pl

.................................................

while (<>) {push (@words, split);}

@sorted = sort { lc $a cmp lc $b || $a cmp $b } @words;
$prev = shift @sorted;
$count = 1;

foreach $i (@sorted) {
if ($i eq $prev) { #$iが前の単語と同じなら,

$count++; #カウンターの値を一つ大きくする。

} else { #違う単語なら,

print "$count\t$prev\n"; #「頻度+タブ+単語」の形式で出力,

$prev = $i; #新しい単語を$prevの値とし,

$count = 1; #カウンターを1に戻す。

}

}
print "$count\t$prev\n"; #最後の単語と頻度を出力
exit;

3.文字列順,あるいは,数値順でソートする

こんなのでいいのかな?左辺から先に評価するということは,数値としてまず考えるということ.数字は文字列としても数値としても読めるので,まず,数値として読む必要があるだろうと思う.文字は数値としては評価されないので(?),この順序でいいだろうと思う.数値読みが優先ということ.


lfujimura0@sv006% more plscript/sort_csv_1.pl
#ソートキーを指定する
print STDERR "SORT KEY: ";
$key = <STDIN>;
chomp;

#全レコードを配列に入れる
while (<>) { chomp; push @records, $_; }

#指定されたキーでソートする
@records_sorted = sort
{ (split ",", $a)[$key]
<=>
(split ",", $b)[$key] ||
(split ",", $a)[$key]
cmp
(split ",", $b)[$key]

}
@records;

#ソートされたものを出力する
foreach $i (@records_sorted) { print "$i\n"; }

exit;

B-4

これで大体いいと思うけれど,$preに入っている語が少ない場合,逆にすると,後ろの方で逆さまになる.どうすればいいのかわからない.

ezkwic2_2.pl

.................................................

print STDERR "SEARCH STRING: ";
$string = <STDIN>;
chomp $string;

print STDERR "left length: ";
$left = <STDIN>;
chomp $left;

print STDERR "right length: ";
$right = <STDIN>;
chomp $right;

$/ = "";
while(<>){
s/ *\n */ /g;
while(/$string/ig){
$count++;
$key = $&;
$post = $';
$pre = substr ($`, -$left);
$pre_revd = join (' ', reverse (split (/\s+/, $pre)));
$file = $ARGV;
$file =~ s#.*/([^/]+)$#$1#;
printf "%5d | %-12.12s | %${left}s|%s|%-${right}.${right}s| %${left}s\n",
$count, $file, $pre, $key, $post, $pre_revd;
}
}
exit;

...............................................................................

最後の項を左詰にすればよいと思うのだけれどできない!

sorted2_2.txt

....................................................................................................

73 | longleg.txt | Dear |Man|, I can't bear to think h|
Dear
12 | longleg.txt | And a |Man|, too! |
a And
19 | longleg.txt | Amasai (hired |man|) in a purple tie and som|
(hired Amasai
32 | longleg.txt | Your secretary |man| has just written to me s|
secretary Your
5 | longleg.txt | Given a tall rich |man| who hates girls, but is |
rich tall a Given
77 | longleg.txt | Then presently the |man| came back and asked me p|
the presently Then
66 | longleg.txt | You are the richest |man| I know. Don't you suppo|
richest the are You
48 | longleg.txt | se of logic. To bring a |man| into line, there are jus|
a bring To logic. of se
64 | longleg.txt | lame for anything. If a |man| believed in fatalism, he|
a If anything. for lame
46 | longleg.txt | larship? I never knew a |man| so obstinate, and stubbo|
a knew never I larship?
70 | longleg.txt | ry. I am certain that a |man| named Elmer H. Griggs mu|
a that certain am I ry.



藤村逸子のホーム