perlによる連番の自動生成

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
yam

perlによる連番の自動生成

#1

投稿記事 by yam » 14年前

初めて投稿させて頂きます。
まずはC言語での質問でない点、何卒お許しください。

現在、独学でPerlを勉強しはじめ、まだ2か月ほどの初心者です。
また以前にもほとんどプログラムの経験がございません。
そのため要領を得ない質問かもしれませんが、そちらについてもお許し頂きたく思います。

質問についてでございますが、ファイルのデータ処理について困っております。
ある「data.txt」というファイルに以下のような改行コードで区切られたデータがあるとします。

##番号:1##
##名前:田中##
##住所:東京##

##番号:2##
##名前:山田##
##住所:大阪##

##番号:3##
##名前:佐藤##
##住所:愛知##

##番号:3##
##名前:小林##
##住所:福岡##

##番号:4##
##名前:太田##
##住所:広島##

……

以上のようなデータが1000件あるとします。
そして「番号」のところをご覧頂きたいのですが、4番目の「番号」は本来なら4なのですが、間違って3となっております。そのため、それ以下の番号が間違って振られております。また1000件のデータには、そのような箇所が所々あるため、最終的に番号は「番号:1020」となっております(本当なら「番号:1000」とならなければなりません)。

そこでperlで連番を自動生成させればよいのではないかと考えました。
具体的には「ファイルの読み込み」→「『番号』の箇所に連番を生成させて、置換する」→「ファイルの書き込み」といったことを考えております。

しかし初心者のためうまくいかず、またネットでサンプルとなるものはないかと探したのですが、こちらもうまく見つけることができませんでした。
そこで皆様のお知恵をお借りしたく、投稿させて頂きました。何卒、よろしくお願い致します。

なお、環境でございますが、

Mac0S 10.4
perl -v 5.8.6
エディタ mi

以上でございます。

再度ながら、何卒、よろしくお願い致します。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: perlによる連番の自動生成

#2

投稿記事 by bitter_fox » 14年前

yam さんが書きました: そこでperlで連番を自動生成させればよいのではないかと考えました。
具体的には「ファイルの読み込み」→「『番号』の箇所に連番を生成させて、置換する」→「ファイルの書き込み」といったことを考えております。

しかし初心者のためうまくいかず、またネットでサンプルとなるものはないかと探したのですが、こちらもうまく見つけることができませんでした。
そこで皆様のお知恵をお借りしたく、投稿させて頂きました。何卒、よろしくお願い致します。
フォーラムルールによりますと
フォーラムルール さんが書きました:   2. どう取り組んで(作ったプログラムはどれで

  3. どのようなエラーやトラブルで困っていて
とありますので、もしyamさんが作ったプログラムがあれば教えていただけますか?

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: perlによる連番の自動生成

#3

投稿記事 by h2so5 » 14年前

yam さんが書きました:そこでperlで連番を自動生成させればよいのではないかと考えました。
具体的には「ファイルの読み込み」→「『番号』の箇所に連番を生成させて、置換する」→「ファイルの書き込み」といったことを考えております。

しかし初心者のためうまくいかず、またネットでサンプルとなるものはないかと探したのですが、こちらもうまく見つけることができませんでした。
そこまで目的にピッタリなサンプルはそうそう無いと思います。
しかし「ファイルの読み込み」、「置換」といった機能別に探していけば方法はだいたい分かるはずです。

実は先ほどPerlの知識がほとんど無い状態で自動生成プログラムを書いてみたのですが、
以下の4つのページに書かれていることを押さえれば作れてしまいました。
(正規表現については知らないとやや戸惑うかもしれませんが、別に難しい使い方をしているわけではありません)

http://www.kent-web.com/perl/chap2.html
http://www.kent-web.com/perl/chap6.html
http://www.kent-web.com/perl/chap7.html
http://www.kent-web.com/perl/chap9.html

答えのコードを書くほどのプログラムではないので、
とりあえずyam さんの手でできるだけ書いてみることをお勧めします。

[追記]
この連番データの場合ですと、正規表現を使わなくても一応は自動生成プログラムを書くことができます。

yam

Re: perlによる連番の自動生成

#4

投稿記事 by yam » 14年前

bitter_foxさん、h2so5さん、わざわざお返事くださり、本当にありがとうございます。
bitter_fox さんが書きました:
フォーラムルール さんが書きました:   2. どう取り組んで(作ったプログラムはどれで

  3. どのようなエラーやトラブルで困っていて
おしゃること、ごもっともです。申し訳ございませんでした。
ただ、こちらが至らないながらも、わざわざご指摘頂いたこと、本当に感謝です。後学に致します。ありがとうございました。
h2so5 さんが書きました: 以下の4つのページに書かれていることを押さえれば作れてしまいました。
(正規表現については知らないとやや戸惑うかもしれませんが、別に難しい使い方をしているわけではありません)

http://www.kent-web.com/perl/chap2.html
http://www.kent-web.com/perl/chap6.html
http://www.kent-web.com/perl/chap7.html
http://www.kent-web.com/perl/chap9.html

答えのコードを書くほどのプログラムではないので、
とりあえずyam さんの手でできるだけ書いてみることをお勧めします。
HPをご紹介頂いたこと、本当に感謝です。参考にさせて頂きました。ありがとうございました。
bitter_fox さんが書きました: もしyamさんが作ったプログラムがあれば教えていただけますか?
h2so5 さんが書きました: この連番データの場合ですと、正規表現を使わなくても一応は自動生成プログラムを書くことができます。
お二人のご指摘を頂き,プログラムを組んでみました(なお、h2so5さんの紹介してくださったHP.参考になりました。ありがとうございました)。

ただ、まだ途中段階であることと、それに関連してまだ途中段階であるために本来の目的とは多少ずれている点がございますが、お許しください。また読み込みのファイル内におけるデータはいちばん最初に質問させて頂いたものである点を、ご了承ください。

コード:

open(FILE, "data.txt");
    $i = 1;
    while(<FILE>){
    chomp;
        if($_ =~ /番号/){
             print $i . $_ , "\n";
             $i++;
        }
}
close (FILE);
【出力結果】
1##番号:1##
2##番号:2##
3##番号:3##
4##番号:3##
5##番号:4##
---------------------

結果としては、「番号」の箇所をうまく抜き出して出力することができました。また行頭の部分ですが連番を振ることができました。

【問題点】
1. 今回はマッチ =~ を使いましたが、「番号:<数字>」の<数字>のところだけを取り出せないものかと悩んでおります。

2. 上記1.と関連して、連番は行頭に出ましたが、行頭ではなく<数字>のところに出ないものかと悩んでおります。

3. 上記1.と2.と関連して、本当はマッチではなく置換(s///)を使って、「番号:」以下の数字の部分を取り出した後、連番を発生させて置き換えたいと考えているのですが、置換をどのように組み合わせて使ってよいのかわかりません。

4. 本来の目的としては、連番を生成させた後、deta.txtに書き込みを行いたいのですが、どのようにしていいのかよくわかりません。h2so5さんからご紹介頂いたHPから(http://www.kent-web.com/perl/chap6.html),ファイルへの書き込みは

コード:

open(FILE,"> data.txt");
print FILE "生成した連番";
close (FILE);
と理解したのですが,生成された連番をどのように処理していいかわかりません(一度、配列のようにして処理するのでしょうか?)。

以上、もしよろしければお教え頂きたく思います。
よろしくお願い致します。

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: perlによる連番の自動生成

#5

投稿記事 by h2so5 » 14年前

yam さんが書きました: 1. 今回はマッチ =~ を使いましたが、「番号:<数字>」の<数字>のところだけを取り出せないものかと悩んでおります。
変数$iに正しい番号が入っているので、わざわざ間違った番号を抽出する必要はありません。
yam さんが書きました: 2. 上記1.と関連して、連番は行頭に出ましたが、行頭ではなく<数字>のところに出ないものかと悩んでおります。
printfを使います。
yam さんが書きました: 3. 上記1.と2.と関連して、本当はマッチではなく置換(s///)を使って、「番号:」以下の数字の部分を取り出した後、連番を発生させて置き換えたいと考えているのですが、置換をどのように組み合わせて使ってよいのかわかりません。
printfを使えば置換は必要ありません。
置換でも不可能ではないですがあまり良い方法ではありません。
yam さんが書きました: 4. 本来の目的としては、連番を生成させた後、deta.txtに書き込みを行いたいのですが、どのようにしていいのかよくわかりません。
data.txtとは別に書き込み用のdata_out.txtなどを開いておき、
data.txtを1行ずつ開きながらdata_out.txtに書き込みを行い、
番号の行の時だけはdata.txtの内容を無視して正しい番号を書き込みます。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: perlによる連番の自動生成

#6

投稿記事 by ISLe » 14年前

perl -ne 's/(番号:)(\d+)/$1.++$i/e;print;' < data.txt
あえて解説しませんがこんな感じで。
参考になるでしょうか。

#ウインドウズのコマンドプロンプトではシングルクォートをダブルクォートに。

(追記)
2つ目の括弧いらなかった。
perl -ne 's/(番号:)\d+/$1.++$i/e;print;' < data.txt

yam

Re: perlによる連番の自動生成

#7

投稿記事 by yam » 14年前

h2so5さん、ISLeさん、お返事ありがとうございます。
何とかうまく連番を生成させ、番号の間違えてある箇所を修正させることができまた。

特に参考になったのが、h2so5さんがご指摘くださった、
h2so5 さんが書きました: data.txtとは別に書き込み用のdata_out.txtなどを開いておき、
data.txtを1行ずつ開きながらdata_out.txtに書き込みを行い、
番号の行の時だけはdata.txtの内容を無視して正しい番号を書き込みます。
の部分でした。このお考えは独学で勉強中のプログラム初心者である私にとっては、考えつかないことでした。
本当に感謝しております。ありがとうございました。

また質問させていただいた「番号」の連番の生成については、結局のところforで生成させ、配列化しました。
他のところ(「名前」と「住所」)についてはdata.txtから読み込みのあとにそれぞれを配列化しました。そしてすべての配列を一つずつ取り出して、新たな .txtに書き込むという手順をとりました。

ただ、せっかくh2so5さんがご指摘くださった、別の書き込み用のファイルを開いてから処理するというのはうまくいきませんでした。そのためターミナル(プロンプト)から直接コマンドを入力して処理しました。
それともう一つ、printfで処理する点もご指摘くださったのですが、こちらにつてもどうしていいかわかりませんでした。
しかし、この2点についてもできるということなので、今後頑張ってチャレンジしたいと思います。

それとISLeさんがお書きくださった、
h2so5 さんが書きました: perl -ne 's/(番号:)\d+/$1.++$i/e;print;' < data.txt
についてもうまくいかなかったのですが、お書きになってくださった内容を理解するためにいろいろ調べて勉強になりましたし、置換のs///を使ってもいけるのだという勉強になりした。この点についても今後チャレンジしてみたいと思います。

以上、皆様、無事に解決することができました。
本当にありがとうございました。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: perlによる連番の自動生成

#8

投稿記事 by ISLe » 14年前

yam さんが書きました:それとISLeさんがお書きくださった、
ISLe さんが書きました: perl -ne 's/(番号:)\d+/$1.++$i/e;print;' < data.txt
についてもうまくいかなかったのですが、お書きになってくださった内容を理解するためにいろいろ調べて勉強になりましたし、置換のs///を使ってもいけるのだという勉強になりした。この点についても今後チャレンジしてみたいと思います。
これはいわゆるワンライナーというもので、端末からperlコマンドを起動するときにコマンドラインでプログラムを指定して、標準入出力に対して1行ずつ処理しています。
そのままだと結果は端末に出力されますのでファイルに記録したいときはリダイレクトします。
CygwinとUbuntuのbashでは動作したのですが。
後学のために出力されたエラーメッセージなど教えていただけないでしようか。

スクリプトに仕立てるとこんな感じになります。

コード:

while(<>){
	s/(番号:)\d+/$1.++$i/e;
	print;
}
in.txtを読み込んでout.txtに書き出すとなるとこんな感じになります。

コード:

open IN, "in.txt";
open OUT, ">out.txt"; # >の直後にファイル名
while(<IN>){
	s/(番号:)\d+/$1.++$i/e;
	print OUT;
}
close OUT;
close IN;

yam

Re: perlによる連番の自動生成

#9

投稿記事 by yam » 14年前

ISLeさん、お返事ありがとうございます。
またスプリクトを示してくださっての詳しい説明にも感謝です。ありがとうございました。
ISLe さんが書きました: そのままだと結果は端末に出力されますのでファイルに記録したいときはリダイレクトします。
CygwinとUbuntuのbashでは動作したのですが。
後学のために出力されたエラーメッセージなど教えていただけないでしようか。
前に「うまくいかなかった」と申し上げましたが、詳細を述べると、ターミナル(プロンプト)にコピペ、または打ち込むと「番号」の部分が文字化けしてしまいました。(こんな感じです→\347\225\252\345\217\267)。
そのため、文字化けが出た時点でうまくいかないものと思い、コマンドを実行させませんでした。
しかし今回文字化けしていても、それを無視して実行したところ、うまく処理されました。
ISLe さんが書きました: in.txtを読み込んでout.txtに書き出すとなるとこんな感じになります。

コード:

open IN, "in.txt";
open OUT, ">out.txt"; # >の直後にファイル名
while(<IN>){
	s/(番号:)\d+/$1.++$i/e;
	print OUT;
}
close OUT;
close IN;
こんなに短いスクリプトでうまく処理できるんですね!
それに比べて私の書いたものなんて、だらだら長くてお恥ずかしいかぎりです(でも生まれて初めてプログラムを書いて、そしてうまく処理されたので、その意味ではちょっと感動しました)。
それと#コメント部分のご指摘も参考になりました。ありがとうございました。

それから先ほどのエラーメッセージで思い出したのですが、ISLeさんがお書きになったスクリプトを実行させたところ、

perl -w data.pl Name "main::i" used only once: possible typo at data.pl line 4.

というメッセージがでました。ただ、処理についてはうまくできていましたので、このメッセージは無視してもいいかとも思うのですが、いかがでしょうか。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: perlによる連番の自動生成

#10

投稿記事 by ISLe » 14年前

yam さんが書きました:perl -w data.pl Name "main::i" used only once: possible typo at data.pl line 4.

というメッセージがでました。ただ、処理についてはうまくできていましたので、このメッセージは無視してもいいかとも思うのですが、いかがでしょうか。
$iという変数が突然出てきてしかも一回しか使われていないのだがタイプミスではないか?という警告ですね。
これに関してはスクリプトを短くするためにあえて無視しました。

ふだんスクリプトを書くときはuse strict&use warningsを付けるようにしています。
本当にタイプミスしたときエラーで弾いてくれます。

コード:

use strict;
use warnings;
open IN, "in.txt";
open OUT, ">out.txt";
our $i; # 変数は宣言が必須になる
while(<IN>){
    s/(番号:)\d+/$1.++$i/e;
    print OUT;
}
close OUT;
close IN;

yam

Re: perlによる連番の自動生成

#11

投稿記事 by yam » 14年前

ISLeさん、お返事拝読致しました。
ISLe さんが書きました: $iという変数が突然出てきてしかも一回しか使われていないのだがタイプミスではないか?という警告ですね。
これに関してはスクリプトを短くするためにあえて無視しました。
なるほど、そう警告だったのですね。
ISLe さんが書きました: ふだんスクリプトを書くときはuse strict&use warningsを付けるようにしています。
本当にタイプミスしたときエラーで弾いてくれます。
私も長いプログラムが書けるようになったら use strict と use warnings を書くようにしなければなりませんね。

ISLeさん、本当にいい勉強になりました。
いろいろご指摘、ありがとうございました。

yam

Re: perlによる連番の自動生成

#12

投稿記事 by yam » 14年前

「そう警告」→「そういう警告」

失礼致しました……(汗)

閉鎖

“C言語何でも質問掲示板” へ戻る