テキストを改行無しの1行に結合する方法を教えて下さい

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
渡辺真

テキストを改行無しの1行に結合する方法を教えて下さい

#1 投稿記事 by 渡辺真 »

改行を含むテキストファイル(IN.txt)を読み込んで、改行をなくした、1行のテキスト(OUT.txt)として出力するプログラムを作りたいと思っています。

(対象とするIN.txtは、4000バイト、全角2000文字程度、半角なら4000文字程度の、空白行を含むテキストです。)

下記のコードを、AB3.13で実行したところ、

①全角700文字(200バイト×7行)程度までは結合できる。

②全角800文字(200バイト×8行)になると、下記エラーになります。

何がマズイのか、どう直したらよいのか、お教え下さい。

なお、lineinputは、淡幻星さんの"LineInput.sbp"を使わせていただいています。
m(__)m

エラーメッセージ
「問題が発生したため、add_text.exe を終了します。 ご不便をおかけして申し訳ありません。
作業途中であった場合、その情報は失われた可能性があります。
この問題を Microsoft に報告してください。」


#N88BASIC
#include "LineInput.sbp"

'■変数宣言
Dim IN_DATA$ As String '<< 取得した文字列を受け取るための変数
Dim Example$ As String '<< 取得した文字列を受け取るための変数
Dim J As Integer
Dim OUT_DATA$ As String
Dim LineL As Integer
Dim command$ As String

' ********************************************************

CLS 3
'********************************
'ファイルのオープン。
Open "c:\test\IN.TXT" For Input As #1
Open "c:\test\OUT.TXT" For Output As #2
'*************データの読み込み***********

J=0
While (Eof(1)=0)
J=J+1
LineInput 1, Example$

print "リンクテキストの";J;"行目を読込み" 'トレース用
print Example$ '***************************トレース用

If Len(Example$)=0 Then
LineL=1

Else
IN_DATA$=IN_DATA$+Example$
LineL=0

End If

print Len(IN_DATA$) '***************************トレース用
print IN_DATA$ '***************************トレース用

Wend
Close 1

OUT_DATA$=IN_DATA$
Print #2 ,OUT_DATA$

'**************終了処理*********************

Close 1
Close #2
input command$
END
渡辺真

解決しました!

#2 投稿記事 by 渡辺真 »

淡幻星さんから、メイルで回答いただきました。

(メイルが行き違いになって、私がこの掲示板にダブルポストしたことを、お詫びいたします。)

淡幻星さんからのメイルには、下記の丁寧な説明があり、この方法で解決しました。(無断引用をご容赦下さい。)

(デバッグ用の画面出力が、エラーの原因だとは皮肉でした。画面の文字が反転していて、おかしいとは思っていましたが。)


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

プロンプトウィンドウへの出力時にエラーが発生していました。
先に解決策から載せますと、
 ・トレース用の[print IN_DATA$]を削除する
もしくは
 ・[print IN_DATA$]を以下のように書き換える
----------------------------------------------
If Len( IN_DATA$ )>128 Then
print Right$( IN_DATA$, 128 )
Else
print IN_DATA$
EndIf
----------------------------------------------
ことでエラー無く動作しました(Ver3.13で確認)。

正確な閾値は分かりませんが、256Byte以上の文字列を10~20回ほど
連続でPrint出力すると、エラーするみたいです。
128Byteでは問題ありませんでした。

 次に、Ver2.xでは問題なく動作し、Ver3.xでエラーする理由ですが、
これはおそらく、Ver2.xではPrint命令をコンパイラ自体が直接解釈して
実行しているのに対して、Ver3.xではWinApi32への書き換えマクロを
通してPrint命令を実行しているためかと思われます。
そのPrint命令の書き換えマクロ(prompt.sbpで定義済み)が、
大きすぎる文字列の、連続Print出力に対して上手く動作しないのだと
思います。

********************************************
hira
記事: 203
登録日時: 2005年5月31日(火) 20:14
お住まい: 兵庫県
連絡する:

エラーの原因は

#3 投稿記事 by hira »

include\basic\prompt.sbp を見てみたところ、(AB4.04.00では) 59~61行目と270~272行目のようです。
以下にその部分のコードを引用します。

[59~61行目]

コード: 全て選択

_PromptSys_Buffer[100]=HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,255)	
_PromptSys_TextColor[100]=HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,255*4)
_PromptSys_BackColor[100]=HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,255*4)
[270~272行目]

コード: 全て選択

_PromptSys_Buffer=HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,255)
_PromptSys_TextColor=HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,255*4)
_PromptSys_BackColor=HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,255*4)


prompt.sbpをじっくり眺めればわかるかと思いますが、実は255バイト分のバッファしか確保されていないんですね(^^;;
これは再描画時の対策のようですが、そのバッファサイズが小さすぎるのでアクセス違反になるということです。
上のコードの「255」の部分をもっと大きい値に変えればエラーは防げました。

※山本さんにバグ報告板で報告しておきます
淡幻星
記事: 183
登録日時: 2005年7月19日(火) 07:02
お住まい: 宮城県
連絡する:

Re: エラーの原因は

#4 投稿記事 by 淡幻星 »

≫渡辺真さん
>メイルが行き違いになって、私がこの掲示板にダブルポストしたことを、お詫びいたします。)
いえいえ、私も返信が随分と遅くなってしまい、すいませんでした。


≫hiraさん
>prompt.sbpをじっくり眺めればわかるかと思いますが
じっくり眺めてませんでした(爆)。
256Byteってのは、「こういうメモリ確保はたいてい255Byteだろう」
って試してみたら、確かにエラーした(それ以下ではエラー無し)ので、
そう書いたのでした。
なるほど。
1行ごとに255Byte確保して、そこにPrint文で渡された文字列を
書き込んでいたんですね。んで TextOut() と。

んーでも、HeapFreeでエラーしているので・・・
あれ、確保したメモリを超えてアクセスした場合ってHeapFreeの個所でエラーするんでしたっけ?
そうだとしても、255Byteを超える文字を出力しても、
すぐにはエラーにならず、しばらく後でエラーするのはなぜでしょうか?

じっくり眺めてみましたが、
PRINT_ToPromptの大体の流れを理解しただけで、
細かいところはわかってないです・・・。
・・・もっとじっくり眺めろってことですね(苦笑)。
もし、気が向きましたら、その当たりを解説していただけると嬉しいです。

いえ、このPrint文でのアクセス違反は、
私も何度か経験してまして、個人的に気になったものでして。
なにはともあれ、山本様のバグフィックスに期待致します(他力願望でスイマセン)。
んー、簡単なのは、Print文で出力できる文字数に上限をつけることでしょうかねぇ。
PRINT_ToPrompt() 内で、上限文字数で切るとか。
hira
記事: 203
登録日時: 2005年5月31日(火) 20:14
お住まい: 兵庫県
連絡する:

#5 投稿記事 by hira »

あれ、確保したメモリを超えてアクセスした場合ってHeapFreeの個所でエラーするんでしたっけ?
そうだとしても、255Byteを超える文字を出力しても、
すぐにはエラーにならず、しばらく後でエラーするのはなぜでしょうか?
他のアプリケーションが使うメモリをいじると、アクセス違反が起こります。しかし、たまたまそのときに他のアプリケーションがその部分にアクセスしていなければ、アクセス違反は出ないこともあります。
HeapFreeでエラーが出るのは、解放時に超えた部分の一部を操作するから…ということになるでしょうか?(あまりうまく説明できませんが)

PRINT_ToPromptですが、内部でDrawPromptBufferという関数が呼び出されています。
こいつのやっていることは、簡単に書けば「文字列をバッファに格納し、文字色や背景色も同時に格納して管理する」で片づいてしまうことになると思います(^^;;
また再描画時(WM_PAINT)には、バッファの内容を使ってもう一度同じ内容を描画させているようです。
淡幻星
記事: 183
登録日時: 2005年7月19日(火) 07:02
お住まい: 宮城県
連絡する:

#6 投稿記事 by 淡幻星 »

素早いレス、ありがとうございます≫hiraさん
解放時に超えた部分の一部を操作するから…
あ、やっぱりそういう理由なんですか。
なんとなく、HeapFree()は、確保後に操作された部分は
全て解放しようとしている気がしてました。
なので、確保領域を越えて操作された部分を解放しようとして、
そこが別のアプリケーションが使っていれば、アクセス違反が起こり、
使ってなければ、運が良かったと言うことでエラー無し、
というように理解しました。
簡単に書けば「文字列をバッファに格納し、文字色や背景色も同時に格納して管理する」
この一言に尽きるみたいですね。
前半が既存のバッファの管理、後半が新規分の追加操作、というとこでしょうか。
すっきりした解説、ありがとうございました。
返信する