プロが教えるわが家の防犯対策術!

perl は初心者です。よろしくお願いします。

★無名ハッシュを作り、リファレンスをハッシュに格納する方法を採用して、試行錯誤しています。

ファイル内容は、論理行の一行毎に行頭が ”AA” のように””で囲まれています。(例文後述)

しかし、行の中には「誤改行」されて正常な行が分割されていて、改行され行頭が””で囲まれていない行が存在します。(正常な行が2分割され、前半部分と後半部分が別な行文となっている)
この「誤改行」を、直前にある「元の正常な分割された前半の行文」と連結して、新たな正常な行としてファイルを修正し新規テキストファイルに書きこみたい。この際、分割されていた2個の「行文」は不要になったので、新規テキストファイルには書き込まない。
この修文作業が、途中まで出来ましたが最後の不要な行の削除が出来ないので、困っています。
------------------------------------------------------------
対象とするテキスト内容 (下記の行番号と文字列は例示です)

1. "ABCD",あいうえおかきくけこ123456789 XXXXXXXXXXXX
2. "EFGH",
3. さしすせそたちつてと9876543 XXXXXXXXXXXX # ←「誤改行」の行です。
4. "IGKL",なにぬねのはひふへほ123456789 XXXXXXXXXXX
5. "MNOP",まみむめもやいゆえよ987654321 XXXXXXXXXXX
6. "QRST",
7. らりるれろわいうえを123456789 XXXXXXXXX # ←「誤改行」の行です。
8.
9.
------------------------------------------------------------------
期待する修文の出力結果 (行内容は、元の行番号の順番と違っても結構です)

1. "ABCD",あいうえおかきくけこ123456789 XXXXXXXXXXXX
2. "EFGH",さしすせそたちつてと9876543 XXXXXXXXXXXX
3. "IGKL",なにぬねのはひふへほ123456789 XXXXXXXXXXX
4. "MNOP",まみむめもやいゆえよ987654321 XXXXXXXXXXX
5. "QRST",らりるれろわいうえを123456789 XXXXXXXXX
6.
7.
-----------------------------------------
私作成したスクリプトの要約は、
# 対象ファイルを一行づつ読み込む.
# 末尾の改行を削除
# 誤改行の場合を正規表現で探す。$ng_gyou に格納
# その他正常行は$ok_gyou, に格納する。
# $falag に誤改行の場合は0、正常な改行の場合は1を格納
# 誤改行の場合の行番号を$count_ng に、正常な改行の場合の行番号を$count_ok に、全部の行番号は$flag_1に格納する。
# 無名ハッシュを作り,リファレンスを $ref に格納する
$ref = {'nomber' => $flag_1,
'ng' => $ng_gyou,
'ok' => $ok_gyou,
'ngcount' => $count_ng,
'okcount' => $count_ok,
'flag' => $flag_ok
};
$WORD{$flag_1} = $ref; # nomber:$flag_1をキーにして,リファレンスをハッシュ:%WORDに格納

# このハッシュ「%WORDを」 読み込んで、処理しました。
foreach $flag_1 ( sort { $a <=> $b } keys %WORD) {
   if($one->{ok} == 0) {
・・・・・・・・・・・・・・・・・
# 細部は、長くなるので省略します。( 誤改行の連結までは成功しましたが、・・・・・・??)

以上、質問内容が冗長になりましたが、どうか御教示下さい。

A 回答 (8件)

>「あらゆるケースに対応したコードを書くのは大変」なので、コード作成は諦めた方が良いのでしょうか!



あらゆるケースに対応することをあきらめれば簡単に書けます。
「行頭が " で始まらない行があれば、前の行に続ける」
だけであれば、私がNo2に書いた sed スクリプトでも良いし、Perlなら、

$x="";
while(<>){ chomp($x) if /^[^"]/; print $x; $x=$_; }
print "\n";

末尾の空行も消えちゃいますが。
    • good
    • 0
この回答へのお礼

御教示を有難うございました。

osamuyさんのANo.4の御教示と同様に「例示のDATA」で成功しました。
-----------------------------------------------------------
< あらゆるケースに対応することをあきらめれば簡単に書けます。
 「行頭が " で始まらない行があれば、前の行に続ける」
-----------------------------------------------------------
★ あらゆるケースに対応することを諦めます!
ベストアンサーには、先に御教授頂いたosamuyさんのANo.4を選ばせて頂きました。
  どうか御寛容の程、お願いします。
付記;
 chomp の使い方を、これから詳しく調べますが全く勉強不足でした。私には、御教授のコードの意味が理解できません。
 while(<>)文で、DATA一行毎に読む込んだ場合において、既に読み込んだ行の前行に遡って前行のDATA内容を処理できるとは、想像できませんでしたので、全部の行を読み込み変数に格納してから、これを取り出して処理する方法を考えていました。

 従って、多重のデータ構造を無名ハッシュのリファレンスで構築しました。検索した「誤改行」の行番号と内容を変数に格納し、直前の行番号と内容を連結させる処理を考えました。行番号をキーにした無名ハッシュのリファレンスを、デリファレンスしながら読み込んだデータを処理すれば、汎用性あるコードになると思案した次第です。

お礼日時:2011/06/07 04:57

例だけを見ていると



行の末にカンマがある場合が誤改行とすれば、
一行読み込み、最後がカンマではなければ、書き出す
カンマであれば、次の行を読んで合わせて、書き出す
というのはどうでしょうか。

一行が複数に誤改行があるようでしたら、
行末がカンマでない行を読むまで、読み込んだものを累積して書き出す
というような事でもよいかと思いますが。
    • good
    • 0
この回答へのお礼

御教示、有難うございます! 私の例示データの説明不足のようです。

例示のデータは「DATAファイル」を、テキストエデターで読み込んで表示される画面を、正確に記述したつもりでした。 
エデターの設定が「行番号・論理行を表示する」とした場合、表示される内容です。
従って、例示の行番号は「DATAファイル」の内容には含まれておらず、行番号が違う行は改行されているのです。
本来は論理行の「一行で表示されるべき行」が分割されている行があるので、「誤改行」と呼称しました。これを直前の行の末尾に連結する方法を求めております。

-----------------------------------------
< 例だけを見ていると・・・・
< 行の末にカンマがある場合が誤改行とすれば、

★ 行末のカンマは関係ありません、誤改行ではありません。
  6."Types of burst","爆発形態・・・ の行をご覧下さい。
  次行の 7.水中核爆発・・・という行は、6."Types of burst"の続きの説明です。
  「誤改行」された内容が、7.水中核爆発・・・ の行です。
-------------------------------------------

以上、「例示したDATA」の説明を補足しました。

お礼日時:2011/06/06 14:06

NO1のお礼を見る限り、「誤改行」というよりは、「データに改行が含まれたCSV」ですね。


CSVは、" " で囲んだ中に改行を入れても良いのです。誤りではありません。

CSVを扱うには、自分であらゆるケースに対応したコードを書くのは大変なので、ライブラリを使うと良いでしょう。
http://search.cpan.org/search?query=CSV&mode=all
    • good
    • 0
この回答へのお礼

notnotさん! 御教示を有難うございました。

 「あらゆるケースに対応したコードを書くのは大変」なので、コード作成は諦めた方が良いのでしょうか!
------------------------------------------------------------
< CSVを扱うには、自分であらゆるケースに対応したコードを書くのは大変なので、ライブラリを使うと良いでしょう。
http://search.cpan.org/search?query=CSV&mode=all
------------------------------------------------------------
ご紹介の方法を、これから勉強してみます。

お礼日時:2011/06/06 07:22

#1 のお礼に書いてある例文で, 「期待する結果」なるものがどのような処理の結果なのか「正確に」書いてみてください.

    • good
    • 0
この回答へのお礼

Tacosan さん!
ご指摘を有難うございます。私の文章が拙くて申し訳ありませんでした。

#1 のお礼に書いてある例文の最後の段落に、「期待する修文した出力」として書いておきましたが、説明不足で申し訳ありませんでした。

 元のデーターの行番号の1~8行が、「期待する修文した出力」においては1~6行になることを期待しています。
元データーの「誤改行」は、行番号の3行目と7行目です。この行を、直前の行の末尾に連結させるので、合計2行が減ります。

お礼日時:2011/06/06 07:03

こことか:


「値に改行コードを含む CSV形式を扱う」
http://www.din.or.jp/~ohzaki/perl.htm#CSVwithCRLF

改行を含んだCSVデータの読み方の話だとしたらですが。
(サンプル7行目「安全高度爆発(safe height burst)」にダブルクォートがついてないのは、typoと予想)。

そうでなく、「先頭が"始まりでなければ前行に追加」というだけなら、こんなのとか:

my $cr = '';
while (<> ){ print $cr if /^"/; $cr = chomp == 0 ? '' : $/; print; }
print $cr;

参考URL:http://www.ideone.com/IPF7C
    • good
    • 0
この回答へのお礼

御教示を有難うございました。私が実際に扱う対象の「例示したデーター」では成功しました。
chompの使い方が勉強不足でよくわかりませんが、便利な方法があるのですね!
------------------------------------------------------
< 「先頭が"始まりでなければ前行に追加」というだけなら、

そのとうりですが、今回のコードを使って前回の例示デターを処理すると、上手くできませんでした。「誤改行」の形が千差万別の感があり規則性はありませんので、如何なる形でも処理できる汎用性のあるコードが、私の願望でありますので宜しく御教示の程お願いします。
< サンプル7行目・・・・
これは、「誤改行」の行で、前行に続く文字列です。
------------------------------------------------------
<「値に改行コードを含む CSV形式を扱う」・・・・・・・・
ご指摘のとうりで、CSV形式の処理方法です。ご教示のWebサイトを見ながら勉強してみます。 対象デターは、約4万行~3万行の数個のcsv形式ファイルです。エデターで正規表現検索で手作業で修正していましたが、月に一度はデターを点検するのでperlを使った処理を勉強中です。千差万別の感がある「誤改行」を、私が手作業で検索(正規表現)する際には、次のように検索したら、概ね全ての「誤改行」をヒットするようでしたので、ご参考になれば幸いです。
/^¥s+|^¥n|^"¥n|^[^"]|^"¥s /

以上、お礼とともに更なるお願いをいたしました。

お礼日時:2011/06/06 06:41

そのまま書いてみました。


動作確認済みです。

#!/usr/bin/perl
use strict;

my @list;

while(<DATA>){
#行末の改行を除去
chomp;
#行頭の数字を除去
s/^\d+\. *//;
#配列に入れておく
push @list, $_;
}

for(my $i=0; $i<@list; $i++){
#行頭の数字は1から始まる
printf("%d. %s", $i+1, $list[$i]);

#異常な行ならば次の行を取り出して繋げる
if($list[$i] =~ /,$/){
printf("%s", splice(@list, $i+1, 1));
}

#改行を出力
printf("\n");
}

__DATA__
1. "ABCD",あいうえおかきくけこ123456789 XXXXXXXXXXXX
2. "EFGH",
3. さしすせそたちつてと9876543 XXXXXXXXXXXX
4. "IGKL",なにぬねのはひふへほ123456789 XXXXXXXXXXX
5. "MNOP",まみむめもやいゆえよ987654321 XXXXXXXXXXX
6. "QRST",
7. らりるれろわいうえを123456789 XXXXXXXXX
8.
9.
    • good
    • 0
この回答へのお礼

懇切な御教示を頂き、有難うございました。

私の質問内容が拙劣で、ご迷惑をかけます。実は行番号はエデターで表示した際の番号であり、ファイル内容には含まれておりません。

このため、行番号を変数に格納して、処理する必要があったのです。
どうも、舌足らずの質問で、誠に申し訳ありませんでした。(osamuyさんのお礼の中で、質問文を補足しました。)

お礼日時:2011/06/05 18:01

この程度はsedで出来そうなのでやってみました。



下記の内容をファイル x に書いて、sed -n -f x 入力ファイル > 出力ファイル で。

1{
h
d
}
/^[^"]/{
H
x
s/\
//
x
d
}
x
p
${
x
p
}
    • good
    • 0
この回答へのお礼

早速の御教示を有難うございました。
sedは以前に使いましたが、細部は手馴れていないので後ほど試してみます。

お礼日時:2011/06/05 16:41

こんな感じ?



while ( <> ){ chomp if /^".+?",$/; print; }

参考URL:http://www.ideone.com/ZsrbL
    • good
    • 0
この回答へのお礼

御教示を有難うございました。
私が例示したファイルでは、お蔭さまで修文が出来ました。

なお、申し訳ありませんが、私の例示したファイル内容文が、適切ではありませんでした。
-----------------------------------------------------------------------------
★実は、次のようなファイルの内容を修文した場合、期待した修文はできませんでした。
(行番号の3行目と、7行目が誤改行です)

1."ACP","aviator continuation pay <空>",""
2."BDS-D","Battlefield Distributed Simulation-Developmental 戦場分散状況シミュレーション; ATD段階<陸><M&S> cf. DIS
3.http://www.fas.org/man/dod-101/army/docs/astmp/c …
4."LZCO","landing zone control officer 降着(着陸/揚陸)地域統制将校(Mil.Terms)",""
5."M","mega メガ; 10(6)、 10の6乗、 百万、 million<SI>",""
6."Types of burst","爆発形態; 空中爆発(airburst)、 フォールアウト回避高度爆発(fallout safe height of burst)、 高空爆発(high airburst)、 高高度爆発(high altitude burst)、 低空爆発(low airburst)、 空中核爆発(nuclear airburst)、
大気圏外核j爆発(nuclear exoatmospheric burst)、 地表接触核爆発(nuclear contact-surface burst)、 地表近接核爆発(nuclear proximity-surface burst)、 地下核爆発(nuclear underground burst)、
7.水中核爆発(nuclear underwater burst)、 最適高度爆発(optimum height burst)、 安全高度爆発(safe height burst) ,""
8."V","Volt ボルト; 電圧/起電力のSI組立単位<SI> ",""
9.
--------------------------------------------------
期待する修文した出力

1."ACP","aviator continuation pay 航空<空>",""
2."BDS-D","Battlefield Distributed Simulation-Developmental 戦場分散状況シミュレーション; ATD段階<陸><M&S> cf. DIS http://www.fas.org/man/dod-101/army/docs/astmp/c …
3."LZCO","landing zone control officer 降着(着陸/揚陸)地域統制将校(Mil.Terms)",""
4."M","mega メガ; 10(6)、 10の6乗、 百万、 million<SI>",""
5."Types of burst","爆発形態; 空中爆発(airburst)、 フォールアウト回避高度爆発(fallout safe height of burst)、 高空爆発(high airburst)、 高高度爆発(high altitude burst)、 低空爆発(low airburst)、 空中核爆発(nuclear airburst)、
大気圏外核j爆発(nuclear exoatmospheric burst)、 地表接触核爆発(nuclear contact-surface burst)、 地表近接核爆発(nuclear proximity-surface burst)、 地下核爆発(nuclear underground burst)、 水中核爆発(nuclear underwater burst)、 最適高度爆発(optimum height burst)、 安全高度爆発(safe height burst) ,""
6."V","Volt ボルト; 電圧/起電力のSI組立単位<SI> ",""
7.
--------------------------------------------------------

▼注記:
 "XXX" で囲った範囲が、一行の中に数個含まれています。

以上、全便の質問内容を変更して申し訳ありませんでした。

お礼日時:2011/06/05 17:48

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