重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

電子書籍の厳選無料作品が豊富!

while(<GO>){
if($_ =~ /BOOK(.+)/){
print OUT "\n$1,";
}
#01234を見つけたら、一番最初の文字列を抜き出す
if($_ =~ /012345 (.+)(.+)(.+)(.+)(.+)(.+) /){

   #その文字列の文末を削除
$data=(.+)
substr($data, -3, 2) = "";
print OUT "$1,";
}
}
close(OUT);

データ例
#####BOOK######
###################33##########################
012345 6.6666ppm 2.6asc 3.9asc GOOD 0 0
012345 1.6666pm 2.6asc 3.9asc NO 0 0
012345 6.6656pppm 2.6asc 3.9asc MIN 0 0
###################36##########################
012346 6.6666ppm 2.6asc 3.9asc GOOD 0 0
012346 1.6666ppm 2.6asc 3.9asc NO 0 0
012346 6.6656ppm 2.6asc 3.9asc MIN 0 0
上記のようなデータから一番左の文字列があったら、
一番最初の文字列を切り出し,文末を削除したいのですが、
作成したperlでは6.6666ppm 2.6asc 3.9asc まで切り出して且文末が削除できません。
どうかアドバイスをお願いします。

A 回答 (11件中1~10件)

>012345 6.6666ppm 2.6asc 3.9asc GOOD 0 0


>========= ====
>print OUT "$1,$2" if /^01234\d+\s+(-?[\d.]+)+\s+\d+\s+\d+s+(\d)/;

\d は数字を意味しますので、(\d+) では GOOD を捕捉することはできません。GOOD, NO, MIN
等の大文字だけの単語をを切り出すには、([A-Z]+) を使うことができます。\s (空白類) と
\S (空白以外) で行の構造にしたがって正規表現を組み立てると、捕捉することができます。

print OUT "$1,$2" if /^01234\d+\s+(-?[\d.]+)\S+\s+\S+\s+\S+\s+([A-Z]+)/;

また、途中を読み飛ばす次のような方法もあります。

print OUT "$1,$2" if /^01234\d+\s+(-?[\d.]+).*\b([A-Z]+)/;
    • good
    • 0
この回答へのお礼

この度は色々とありがとうございました。
もう少しアドバイスいただきたいのですが当初の疑問は解消できました。ありがとうございました。

お礼日時:2008/10/22 20:36

No9 の回答に書き間違いがありました。

2行目の (-?[\w.]+) を (-?[\d.]+) に訂正します。
    • good
    • 0
この回答へのお礼

ありがとうございます。
もうひとつアドバイスをいただきたく、よろしくお願いします。
・以下のように6.6666と合わせてGOODを出力したい時はどのように
すればよいですか?うまくいきません。

012345 6.6666ppm 2.6asc 3.9asc GOOD 0 0
========= ====
print OUT "$1,$2" if /^01234\d+\s+(-?[\d.]+)+\s+\d+\s+\d+s+(\d)/;

お礼日時:2008/10/21 23:09

>1.抜き出す数字はマイナスのときはどうしたらよろしいでしょうか?


丸カッコの先頭に -? (- が0個または1個) を付けて、(-?[\w.]+)のようにすると抜き出すことができます。

>2.抜き出す数字の小数点以下が.0000のときはエクセルに出力するには?
エクセルを使ったことがないのでお答えできません。

>3.012345と012346のデータ間で改行をいれるにはどうしたらよろしいでしょうか?
# に囲まれた数字の行を利用することができると思います。次のコードは、先頭に数字そのものを
出力しています。

while (<GO>) {
print OUT "\n$1," if /^#+(\d+)#+/;
print OUT "$1," if /^01234\d+\s+(-?[\d.]+)/;
}
    • good
    • 0

次のような簡単なコードで十分ではないかと思います。

ただ、BOOK に続く ######
は意味のあるデータとは思えませんが?

while (<GO>) {
print OUT "\n$1," if /BOOK(.+)/;
print OUT "$1," if /^01234\d+\s+([\d.]+)/;
}
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
追加でお聞きしたいことがあります。どうかお答えいただきたく、
よろしくお願いします。
1.抜き出す数字はマイナスのときはどうしたらよろしいでしょうか?
2.抜き出す数字の小数点以下が.0000のときはエクセルに出力するには?
3.012345と012346のデータ間で改行をいれるにはどうしたらよろしいでしょうか?

お礼日時:2008/10/20 23:04

レコード(行)の先頭にある空白の扱いが微妙に違いますが、


フィールドの区切りに関して言えば、/ / は単にスペース一個という
解釈はされませんので、修正する必要はありません。

As a special case, specifying a PATTERN of space (' ') will
split on white space just as "split" with no arguments does.
Thus, "split(' ')" can be used to emulate awk's default
behavior, whereas "split(/ /)" will give you as many null
initial fields as there are leading spaces. A "split" on "/\s+/"
is like a "split(' ')" except that any leading whitespace
produces a null first field. A "split" with no arguments really
does a "split(' ', $_)" internally.

>後日譚。今思えば、この正規表現は全然へなちょこでした。
>[+-]?\d*?.?\d+

小数点を表すピリオドはエスケープする必要があるのではありませんか?


まあそういうことで。
    • good
    • 0

4行目を


my ($num, $ppm) = split / +/;
とすれば、スペース1個以上で分割できます。なお、より一般的に空白文字で分割するには:
my ($num, $ppm) = split /\s+/;
こんな感じですね。

7行目
push @ppm, $ppm =~ /(\d?.?\d+)/;
にご注目ください。
後方参照のためのグループ化を使用した正規表現によるパターンマッチをリストコンテキストで評価すると、マッチした部分をリストで返します。

――つまり、カッコ内の正規表現にマッチしたやつが、@ppm に追加されるわけです。
ところで、「カッコ内の正規表現」って何でしょうか ?
\d?.?\d+
↑実はこれは、数字部分にマッチする正規表現です。
数字部分のみを抜き出して、@ppm に追加することができるわけです。
数字以降にいかなる文字列があろうとも、数字だけを抽出することができます。

後日譚。今思えば、この正規表現は全然へなちょこでした。
[+-]?\d*?.?\d+
せめてこれくらいはしないとダメですね。
    • good
    • 0

間違えました。

正しくはこちらです。

----------
my @ppm;

while (<GO>) {
my ($num, $ppm) = split / /;
next unless defined $num and defined $ppm;
next unless (substr $num, 0, 5) eq '01234';
push @ppm, $ppm =~ /(\d?.?\d+)/;
}

print OUT join ',', @ppm;
----------

7c7
< push @ppm, $ppm;
---
> push @ppm, $ppm =~ /(\d?.?\d+)/;

この回答への補足

回答ありがとうございます。
いつくか教えていただきたいことがあります。
(1)文末がpppmやpmの文字列も「my @ppm;」で抜けるのはなぜですか?
(2)下記のようにスペースが長いときもあるのですがそれも考慮して、
抜き出す方法はございますか?
012345      6.6666ppm 2.6asc 3.9asc GOOD 0 0
よろしくお願いいたします。

補足日時:2008/10/18 23:02
    • good
    • 0

my @ppm;



while (<GO>) {
my ($num, $ppm) = split / /;
next unless defined $num and defined $ppm;
next unless (substr $num, 0, 5) eq '01234';
push @ppm, $ppm;
}

use 5.010000;
say OUT join ',', @ppm;
    • good
    • 0

なんとなくこういうこと?



use strict;
use warnings;
use feature ':5.10';

open my $output, '>', 'sample.out';

while(my $line = <DATA>){
chomp $line;
if($line =~ /BOOK(.+)/){
print $output "\n$1,";
}
#01234を見つけたら、一番最初の文字列を抜き出す
if($line =~ /^01234/){
my ($num, $item1, $rest) = split / /, $line;
print $output "$item1,";
}

}
close $output;

__END__
#####BOOK######
###################33##########################
012345 6.6666ppm 2.6asc 3.9asc GOOD 0 0
012345 1.6666pm 2.6asc 3.9asc NO 0 0
012345 6.6656pppm 2.6asc 3.9asc MIN 0 0
###################36##########################
012346 6.6666ppm 2.6asc 3.9asc GOOD 0 0
012346 1.6666ppm 2.6asc 3.9asc NO 0 0
012346 6.6656ppm 2.6asc 3.9asc MIN 0 0


結果

######,6.6666ppm,1.6666pm,6.6656pppm,6.6666ppm,1.6666ppm,6.6656ppm,

最初に空行はいるとか、末尾にも','が付くってのはたぶんNGなんでしょうねえ。
んで、元データの#の行をじーっとみてみて

33,6.6666ppm,1.6666pm,6.6656pppm
34,6.6666ppm,1.6666ppm,6.6656ppm

とか

33,6.6666ppm,2.6asc,3.9asc
33,1.6666pm,2.6asc,3.9asc
33,6.6656pppm,2.6asc,3.9asc
34,6.6666ppm,2.6asc,3.9asc
34,1.6666ppm,2.6asc,3.9asc
34,6.6656ppm,2.6asc,3.9asc

みたいな結果がほしいのかなあと思わないでもないんですがどうなんでしょうか?

この回答への補足

説明がうまくなく、すいません。
出力イメージは以下のような感じです。
●出力イメージ
6.6666,1.6666,6.6656,6.6666,1.6666,6.6656,

補足日時:2008/10/18 21:00
    • good
    • 0

スクリプトを見ても、正規表現がめちゃくちゃなので欲しい結果がどういうものかわかりません。



>012345 6.6656pppm 2.6asc 3.9asc MIN 0 0

>012346 6.6656ppm 2.6asc 3.9asc MIN 0 0

>上記のようなデータから一番左の文字列があったら、
>一番最初の文字列を切り出し,文末を削除したいのですが、
>作成したperlでは6.6666ppm 2.6asc 3.9asc まで切り出して且文末が削除できません。

一番左の文字列を切り出し文末を削除というのは
この例だと 6.6656ppm だけとれればいいんですか?

この回答への補足

>一番左の文字列を切り出し文末を削除というのは
>この例だと 6.6656ppm だけとれればいいんですか?
はい。それでppmを取りたいです。

簡単ですが、よろしくお願いします。

補足日時:2008/10/18 21:09
    • good
    • 0

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