プロが教える店舗&オフィスのセキュリティ対策術

あるデータファイル中に以下のようなデータがあります。
>1234
adjaiubgubmcauouamaouagamouaucamougauyouajmouaguau
zadaaboueroauahcaoqqpeuaoqueiiulgjaogahiapnnfaugao


>1235
ajfaoufaobayanfaggsofudjjmlacxaoueytiaulmfglaguaou
agaohghmfjghucpoepppppfagaaewetfhafhdaugyaiygyaygi


>1236


「>・・」はそれ以下の文字列のIDをあらわしています。各文字列はそれぞれIDを持っています。IDごとに30文字の文字列を(ランダムに)x回抽出するプログラムを教えてください。考えているうちにぜんぜんわからなくなりました。取得した文字列は元のデータファイル中に以下のように上書きをしたいです。「>」以下にはその文字列を取得したIDとそのID内のデータの何行目から何行目までのデータを取得したかを表す
タグがほしいです。そのような仕様の文字列取得作業を全部でランダムにX回したいと考えております。以下の実行例のように取得する文字列は一部かぶってもぜんぜん結構です。
昨日から考えていますが、限界に来ました。
長い説明になって申し訳ございませんが、よろしくお願いします。

≪元のデータファイルに上書きされた実行例≫
>1234from1to30
adjaiubgubmcauouamaouagamouauc
>1236from51to81
aijewqmikfugpoirexcxgragukgewj
>1235from47to77
guauzadaaboueroauahcaoqqpeuaoq

A 回答 (2件)

$line =~ /^>(\d+)/



上の式では正規表現で文字列$lineのパターンマッチを行っています.
式のおおざっぱな意味は「$lineは'>'で始まり,数字が1回以上連続する文字列か?またYESなら数字の部分を取得($1に代入)せよ」です.

ifステートメントの式として指定しているので,このときの$lineの中身が'>1234'となっていればifの判定式は真となり,$1に'1234'という文字列が代入されます.
正規表現に関して,詳しくは参考URLをご覧ください.(もしくは検索してください.)

さて,IDの書かれている行は

>">ID|12345678|・・・"という風になっていまして

とのことですので,正規表現をこれにあわせる必要があります.(言葉の説明を読む限りでは">ID|12345678・・・|"のタイプミスでしょうか.これくらいならみて気づく範囲なので問題ありません.が,お仕事で自分の作成したスクリプトの仕様を書く場合はご注意ください.《なんだか偉そうなことをいってますね.すみません.》)

ifのかっこの中を次のように書き換えてみてください.

$line =~ /^>ID|(\d+)|/

これで,きちんと動くと思います.

****************************************

Perlの本を知りたいとのことですが,Perlはもともとテキスト処理に優れた言語らしいので,Perlの入門書をうたっている本であればどの本でも,ファイル処理や文字列処理に関する基本事項は書かれていると思います.

このサイトにいらっしゃるほかの多くのPerlユーザの方々と比べると私はまだPerlに出会ってから日が浅い―自己紹介にもあるとおり10ヶ月ほどです―ので,私の勧めるものが参考になるかどうかといえば疑問符がつきますが,武藤健志さんの「独習Perl」と結城浩さんの「Perl言語プログラミングレッスン[入門編]」をお勧めします.

私はまず「独習Perl」をサンプルコードを打ちながらザッと読んで感覚をつかみ,「プログラミングレッスン」でじっくり理解していきました.

現在の私のPerlに関する知識は「プログラミングレッスン」によるところが大きいので,こちらだけでもよいかもしれません.この本があらかた理解できるようになったら,「初めてのPerl」や「続・初めてのPerl」といった少し格式の高い本に手を出しても,自分で読み進められると思います.

それと,リファレンスとしてPerlコマンド辞典のようなものが手元にあると便利です.知っているコマンドの詳細はperldocで調べれば済みますが,知らないコマンドについてもそれが何をするためのコマンドなのか概要とサンプルコードが書かれているはずなので,暇なときにパラパラめくって読むといいかもしれません.

参考URL:http://perl.misty.ne.jp/16.html#a,http://www.toh …
    • good
    • 0
この回答へのお礼

ありがとうございました。
おかげで正規表現を勉強し、うまく動きました。
本を買おう買おうと思っていたんですが、何を買ったらいいのか
わからなかったので、ぜひ推薦していただいた本を買って勉強します。
またよろしくお願いします。

お礼日時:2008/07/31 09:08

※以下の確認では,あるID"A"から文字列を抽出し"AfromMtoN"を作成する作業を「IDを使用する」と表現しています.



>「>・・」はそれ以下の文字列のID
IDは数字のみで構成されているのですか.

>IDごとに30文字の文字列を(ランダムに)x回抽出する
>文字列取得作業を全部でランダムにX回
xとXは同じものを指していますか.
また,Xの値が小さければ当然使われないIDも出てきます.逆にXの値が大きければ同じIDを複数回使用することになります.よろしいですか.

>取得する文字列は一部かぶってもぜんぜん結構です
「かぶる=同じIDを複数回使用すること」ですか.そうだとすると,一方で使用しないIDがあってもよろしいですか.

>ID内のデータの何行目から何行目までのデータ
行ではなく文字ですよね.

>元のデータファイル中に以下のように上書きをしたい
上書きということは,元のデータは残す必要はありませんね.


下のスクリプトは以上の確認内容がすべて肯定された場合を想定しています.

****************************************

use strict; # 厳密な文法チェック

my $file = 'text';
my $len = 30; # 抽出する文字列の長さ
my $x_max = 100; # 最大抽出回数

my ($fh, $id, @keys, $n, %data, %out, $x);

# データの読み込み
open $fh, "+< $file" or die $!;
while(my $line = <$fh>){
chomp $line;
if($line =~ /^>(\d+)/){ # IDが書かれている行なら
$id = $1; # IDをハッシュのキーとして保存
$keys[$n++] = $id; # IDを配列に格納
}else{ # データが書かれている行なら
$data{$id} .= $line; # ハッシュにデータを追記
}
}

# 新規データの生成
$x = int(rand $x_max) + 1; # データ抽出回数を設定
for(1 .. $x){
$n = $keys[int rand @keys]; # 文字列を取り出すIDをランダムに決定
my $from = int rand(length($data{$n}) - $len); # 文字列の取得開始位置
$id = $n . "from" . $from . "to" . ($from + $len - 1); # 新規データのID
redo if(defined $out{$id}); # すでに同じデータがあればやり直し
$out{$id} = substr $data{$n}, $from, $len; # 出力用ハッシュに新規データを追加
}

# 不要データの削除
undef %data;
undef @keys;

# ファイル内容の消去
seek $fh, 0, 0;
truncate $fh, 0;

# 新規データの書き込み
while(my ($key, $value) = each %out){
print $fh ">", $key, "\n", $value, "\n";
}

close $fh or die $!;

この回答への補足

回答ありがとうございました。
いつも__awa__さんにはお世話になり、ありがとうございます。
返事が遅くなり、申し訳ございませんでした。

>>「>・・」はそれ以下の文字列のID
>IDは数字のみで構成されているのですか.
すいません、説明が足りなかったです。実際に使用するIDは
">ID|12345678|・・・"という風になっていまして抽出する時は、数字部分の"12345678"を抽出したいと考えています。数字の桁数は指定がありません。プログラムを拝見してこの部分がわかりませんでした。

>>IDごとに30文字の文字列を(ランダムに)x回抽出する
>>文字列取得作業を全部でランダムにX回
>xとXは同じものを指していますか.
xとXは同じものです。私のタイプミスです。すいません。

>また,Xの値が小さければ当然使われないIDも出てきます.逆にXの値が大きければ同じIDを複数回使用することになります.よろしいですか.
結構です。そっちのほうが自然です。

>>取得する文字列は一部かぶってもぜんぜん結構です
>「かぶる=同じIDを複数回使用すること」ですか.そうだとすると,一方で使用しないIDがあってもよろしいですか.
かぶるというのは、例えば、一回目でIDが"12345678"の文字列を31番目から60番目までを取得したとします。4回目でIDが"12345678"(1回目と同じID) の文字列を41番目から70番目を取得したとすると、1回目と比較して、文字列41番目と60番目が重複して取得します。このことをかぶると表現しました。紛らわしくてすいませんでした。

>ID内のデータの何行目から何行目までのデータ
行ではなく文字ですよね.
そうです。文字列の何番目から何番目という意味でした。私のミスです。

>元のデータファイル中に以下のように上書きをしたい
上書きということは,元のデータは残す必要はありませんね.
そうです。元のデータは残す必要はないです。

あともう一つ質問なんですが、仕事で、上で質問したようなPerlのファイル操作、文字列操作のプログラムを作成する必要がありまして、そこらへんの知識やスキルを身につけたいのですが、そこらへんのことが詳しく書かれているおすすめの本とかあれば教えていただけないでしょうか?

よろしくお願いします。

補足日時:2008/07/28 11:01
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!