文字列から空行を削除するには?

解決


かえで  2004-02-17 03:30:16  No: 7164  IP: [192.*.*.*]

改行を含んだ文字列から空行を削除したいのですが、

var
  SL: TStringList;
  i: Integer;
begin
  SL := TStringList.Create;
  try
    SL.Text := Value; // Valueに文字列が入っている
    for i := SL.Count - 1 downto 0 do
      if SL[i] = '' then
        SL.Delete(i);
    Value := SL.Text;
  finally
    SL.Free;
  end;
end;

この方法だと文字列の最後に改行が無いときうまくいきません。
どうすれば空行だけを削除できるでしょうか?
それと、TStringListを使わない方法がありましたら教えてください。

編集    削除
るるとん@K  2004-02-17 03:40:46  No: 7165  IP: [192.*.*.*]

私は普段for文は使わないので良く分かりませんが
SL.Count-1の部分がSL.Countだけで良いような気がします
var
SL:・TStringList;
i:・Integer;
begin
SL・:=・TStringList.Create;
try
SL.Text・:=・Value;
i:=0;
while・i・<・SL.Count・do
begin
if・SL[i]・=・''・then
SL.Delete(i);
end;
Value・:=・SL.Text;
finally
SL.Free;
end;
end;
ですかな

編集    削除
るるとん@K  2004-02-17 03:41:54  No: 7166  IP: [192.*.*.*]

何か文字化けしてますね

編集    削除
jok  2004-02-17 03:46:25  No: 7167  IP: [192.*.*.*]

> この方法だと文字列の最後に改行が無いときうまくいきません。

そうなの? 試したところではうまくいくようですけど。

編集    削除
るるとん@K  2004-02-17 03:48:46  No: 7168  IP: [192.*.*.*]

>・この方法だと文字列の最後に改行が無いときうまくいきません。
たぶん最後の行まで実行されて無いだけだとおもいます

編集    削除
るるとん@K  2004-02-17 03:56:40  No: 7169  IP: [192.*.*.*]

var
s:string;
begin
while ansipos(#13#10#13#10,s) do
begin
StringReplace(s,#13#10#13#10,#13#10,[rfReplaceAll]);
end;
if s[length(s)-1]+s[length(s)] = #13#10 then
begin
s:=leftstr(s,length(s)-2);
end;
end;

編集    削除
るるとん@K  2004-02-17 03:59:00  No: 7170  IP: [192.*.*.*]

ミッス!!
危険、無限ループ
StringReplace(s,#13#10#13#10,#13#10,[rfReplaceAll]);
ではなく
s:=StringReplace(s,#13#10#13#10,#13#10,[rfReplaceAll]);

編集    削除
にしの  2004-02-17 04:06:33  No: 7171  IP: [192.*.*.*]

それだと、#13#10#13#10#13#10が、#13#10#13#10になり、空行が残ります。
# 無限ループにはなりませんよ。
# 処理後の場所は処理されません。

また、先頭の空行は、#13#10のみですので、別途処理が必要です。


最後の行が改行の時問題であれば、最後にダミーの行を追加してからTStringListに入れれば対処できますね。

編集    削除
にしの  2004-02-17 04:15:53  No: 7172  IP: [192.*.*.*]

るるとん@Kさん、失礼しました。
ちゃんと処理されていましたね。
よく見ず発言してました。

編集    削除
にしの  2004-02-17 04:30:52  No: 7173  IP: [192.*.*.*]

こんなのを作っていました。文字列が大きいと遅いと思います。細かくはチェックしていません。

function DelEmptyLine(const str: String): String;
var
  s: String;
  p: PCHAR;
  prev: Char;
begin
  s := AdjustLineBreaks(str, tlbsLF);//#$Aに変更

  p := PCHAR(s);
  Result := '';
  prev := ' ';
  while p^=#10 do Inc(p);
  while p^ <> #0 do
  begin
    if (prev=#10) and (p^=#10) then
    begin
      Inc(p);
      Continue;
    end;
    Result := Result + p^;
    prev := p^;
    Inc(p);
  end;
  Result := AdjustLineBreaks(Result);
end;

作って気がついたのですが、文字列最後の改行を、最後に空行があると見なすのでしょうか。
# 上に書いたプロシージャでは、最後の改行は空行とは見なしていません。

編集    削除
るるとん@K  2004-02-17 04:51:05  No: 7174  IP: [192.*.*.*]

>また、先頭の空行は、#13#10のみですので、別途処理が必要です。
これでOK
var
s:string;
begin
while ansipos(#13#10#13#10,s)>0 do
begin
s:=StringReplace(s,#13#10#13#10,#13#10,[rfReplaceAll]);
end;
if s[length(s)-1]+s[length(s)] = #13#10 then
begin
s:=leftstr(s,length(s)-2);
end;
if ansipos(#13#10,s)=1 then
begin
s:=stringreplace(s,#13#10,'',[])
end;
end;

編集    削除
かえで  2004-02-17 07:01:07  No: 7175  IP: [192.*.*.*]

> 私は普段for文は使わないので良く分かりませんが
> SL.Count-1の部分がSL.Countだけで良いような気がします
for文にしたのは一番高速だと教わったからです。
繰り返しの回数がわかっているときはfor文を使う方が良いらしいです。

> 文字列最後の改行を、最後に空行があると見なすのでしょうか。
自信は無いのですが、空行というのは「改行コードの前に文字が無い行」
ではないかと思います。

るるとん@Kさん、コードを書いてくださってありがとうございます。
ですが、同じ方法を以前試したことがあり、文字列が大きいと遅くて
実用になりませんでした。

にしのさんの方法を使わせていただきます。
どうもありがとうございました。

編集    削除