Trim関数で大文字スペースもTrim対象にしたい

解決


kaizarsome  2005-04-14 23:24:05  No: 14314

Delphi5を使っているのですが、
Trim関数の削除対象にて全角スペースは削除されないようです。
全角スペースも削除対象にするにはどうしたらよいでしょうか?
ご指導お願いします。


deldel  2005-04-14 23:41:53  No: 14315

ShowMessage(StringReplace('hoge  ほげ  hoge  ほげ', '  ', '', [rfReplaceAll]));


傍観者  2005-04-14 23:50:12  No: 14316

> ShowMessage(StringReplace('hoge  ほげ  hoge  ほげ', '  ', '', [rfReplaceAll]));
失礼ですが、Trimとは動作が違っているのではないですか?

(ヘルプより)
Trim関数は文字列から先頭部分および末尾部分の空白と制御文字を取り除きます。


kaizarsome  2005-04-14 23:50:47  No: 14317

あ〜!StringReplace!
盲点でした。頭が固かったようです。。。
deldelさん、ご指導ありがとうございました。


kaizarsome  2005-04-14 23:52:32  No: 14318

>傍観者様
確かに・・・
処理の目的によっては、これでいいのですが、
やはりTrimで大文字スペースを削除したいです。


木星人  2005-04-14 23:58:11  No: 14319

//自分で関数を作るのが一番早いんじゃないでしょうか

const
  ZenkakuSpace = '  ';

function MBTrimRight(s : string) : string;
var
  i : Integer;
begin
  i := Length(s);
  while i >= 1 do
  begin
    case ByteType(s,i) of
    mbSingleByte:
      if s[i] > #$20 then
        Break;
    mbLeadByte:
      Break;
    mbTrailByte:
      if (s[i] = ZenkakuSpace[2]) and (s[i-1] = ZenkakuSpace[1]) then
        Dec(i)
      else
        Break;
    end;
    Dec(i);
  end;
  Result := Copy(s,1,i);
end;

function MBTrimLeft(s : string) : string;
var
  i : Integer;
begin
  i := 1;
  while i < Length(s) do
  begin
    case ByteType(s,i) of
    mbSingleByte:
      if s[i] > #$20 then
        Break;
    mbLeadByte:
      if (s[i] = ZenkakuSpace[1]) and (s[i+1] = ZenkakuSpace[2]) then
        Inc(i)
      else
        Break;
    mbTrailByte:
      Break;
    end;
    Inc(i);
  end;
  Result := Copy(s,i,MaxInt);
end;

function MBTrim(s : string) : string;
begin
  Result := MBTrimLeft(MBTrimRight(s));
end;


kaizarsome  2005-04-15 00:04:37  No: 14320

>木星人様
SysUtilsのTrim関数を改造して、別名で関数にする事にします。
Delphiはまだまだ初心者レベルなので、ソース参考にさせて頂きます。

ご指導ありがとうございました。


deldel  2005-04-15 00:09:38  No: 14321

ぢゃ、これは?

function Trim2(S: string): string;
begin
  if Copy(S, 1, 2) = '  ' then S := Copy(S, 3, Length(S));
  if Copy(S, Length(S) - 1, 2) = '  ' then S := Copy(S, 1, Length(S) - 2);
  Result := S;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage('<' + Trim2('  hogeほげ  ') + '>');
  ShowMessage('<' + Trim2('hogeほげ  ') + '>');
  ShowMessage('<' + Trim2('  hogeほげ') + '>');
  ShowMessage('<' + Trim2('hogeほげ') + '>');
  ShowMessage('<' + Trim2('  hoge  ほげ') + '>');
end;


傍観者  2005-04-15 00:30:28  No: 14322

> Trim2
両端の全角スペースを取り除く関数になっていませんか?
全角スペースが両端にあるとは限らないですよね。


deldel  2005-04-15 00:33:03  No: 14323

Trim2関数は文字列から先頭部分および末尾部分の全角スペースを取り除きます。


メラトニン  2005-04-15 00:33:05  No: 14324

deldelさん
('                hogeほげ                  ')
の処理〜!
木星人さんのレスをちゃんと読みましょう。


deldel  2005-04-15 00:34:10  No: 14325

傍観者さん、メラトニンさん、おおぼけでした。
すみませんm(_`_)m


kaizarsome  2005-04-15 00:35:54  No: 14326

皆様、色々ご指導ありがとうございます。

こんなんが出来ました。
早速テストしてみます。

function TrimMB(const S: string): string;
var
  tmpS: String;
begin
  tmpS := S;

  while (Copy(tmpS, 1, 1) = ' ') and (Copy(tmpS, 1, 2) = '  ') do
  begin
    if Copy(tmpS, 1, 1) = ' ' then
      tmpS := Copy(tmpS, 2, Length(tmpS));
    if Copy(tmpS, 1, 2) = '  ' then
      tmpS := Copy(tmpS, 3, Length(tmpS));
  end;

  while (Copy(tmpS, Length(tmpS), 1) = ' ') and (Copy(tmpS, Length(tmpS) -1, 2) = '  ') do
  begin
    if Copy(S, Length(S), 1) = ' ' then
      S := Copy(S, 1, Length(S) - 1);
    if Copy(S, Length(S) - 1, 2) = '  ' then
      S := Copy(S, 1, Length(S) - 2);
  end;

  Result := tmpS;
end;


deldel  2005-04-15 00:41:14  No: 14327

以下ではだめでしたね。
ShowMessage('<' + TrimMB('       hoge  ほげ       ') + '>');
木星人さんので、ばっちりだと思いますが・・・?


kaizarsome  2005-04-15 00:42:14  No: 14328

さきほどのソースは、凡ミスだらけでした。
修正したソースです。いい感じで動いてます。
木星人様、deldel様のソースを参考に作りました。
他の皆様もご指摘ありがとうございました。

{*** 以下ソース ***}
function TForm1.TrimMB(const S: string): string;
var
  tmpS: String;
begin
  tmpS := S;

  while (Copy(tmpS, 1, 1) = ' ') or (Copy(tmpS, 1, 2) = '  ') do
  begin
    if Copy(tmpS, 1, 1) = ' ' then
      tmpS := Copy(tmpS, 2, Length(tmpS));
    if Copy(tmpS, 1, 2) = '  ' then
      tmpS := Copy(tmpS, 3, Length(tmpS));
  end;

  while (Copy(tmpS, Length(tmpS), 1) = ' ') or (Copy(tmpS, Length(tmpS) -1, 2) = '  ') do
  begin
    if Copy(tmpS, Length(tmpS), 1) = ' ' then
      tmpS := Copy(tmpS, 1, Length(tmpS) - 1);
    if Copy(S, Length(S) - 1, 2) = '  ' then
      tmpS := Copy(tmpS, 1, Length(tmpS) - 2);
  end;

  Result := tmpS;
end;


Fusa  2005-04-16 10:38:31  No: 14329

みなさん...こういうときって
将来の汎用性を考えて手続き書かない?

全角だけじゃなくて、全ての文字で
動作するように対応しておきたくなったり
先頭と末端指定も書きたくなったり、、、

それにファーストテストも実施するべき。
そうしておくとバグが減らせる。
このスレで起きてたような凡ミスも防止できるし
関数の信頼性やリファクタリングのような応用にもつながるよ。

const
  EmptyStr: WideString = '';

function TrimLeftChar(S: WideString; Table: WideString): WideString;
var
  i: Integer;
  WriteIndex: Integer;
  TrimFlag: Boolean;
begin
  SetLength(Result, Length(S));
  WriteIndex := 0;
  TrimFlag := True;
  for i := 1 to Length(S) do
  begin
    if not (TrimFlag and (1<=Pos(S[i], Table))) then
    begin
      TrimFlag := False;
      Inc(WriteIndex);
      Result[WriteIndex] := S[i];
    end;
  end;
  SetLength(Result, WriteIndex);
{ -----------------------------------
  //低速だがコードが短い方の実装
begin
  while (S<>EmptyStr) and (1<=Pos(S[1], Table))  do
    Delete(S, 1, 1);
  Result := S;
end;
//----------------------------------- }
end;

function TrimRightChar(S: WideString; Table: WideString): WideString;
var
  i: Integer;
  WriteIndex: Integer;
begin
  Result := S;
  WriteIndex := Length(Result);
  for i := Length(S) downto 1 do
  begin
    if (1<=Pos(S[i], Table)) then
    begin
      Dec(WriteIndex);
    end else
    begin
      break;
    end;
  end;
  SetLength(Result, WriteIndex);
{ -----------------------------------
  //低速だがコードが短い方の実装
begin
  while (S<>EmptyStr) and (1<=Pos(S[Length(S)], Table)) do
    Delete(S, Length(S), 1);
  Result := S;
end;
//----------------------------------- }
end;

function TrimChar(S: WideString; Table: WideString): WideString;
begin
  Result := TrimLeftChar(TrimRightChar(S, Table), Table);
end;

procedure Check(A, B: String);
begin
  if not(A = B) then
  begin
    raise Exception.Create('エラーです ' + A + ':' + B);
  end;
end;

procedure testTrimLeftChar;
begin
  Check('あ', TrimLeftChar('    あ', '  '));
  Check('う', TrimLeftChar('      う', '  '));
  Check('か', TrimLeftChar('あいうえおああいいか', 'あいうえお'));
  Check('X', TrimLeftChar('    YY  X', '  Y'));
  Check('789', TrimLeftChar('012346789', '6543210'));
  Check('ABCXYZ', TrimLeftChar('XXYYZZABCXYZ', 'XYZ'));
  Check('', TrimLeftChar('XXYYZZABCXYZ', 'XYZABC'));
  Check('AAA'#9, TrimLeftChar(#9'AAA'#9, #9));
  Check(#9, TrimLeftChar('AAA'#9, 'A'));
  Check(#9'AAA', TrimLeftChar(#13#10#9'AAA', #13#10));
  Check(#13#10, TrimLeftChar(#9'AAA'#13#10, #9'A'));
  Check('123', TrimLeftChar('123', ''));
end;

procedure testTrimRightChar;
begin
  Check('    ', TrimRightChar('    あ', 'あ'));
  Check('あいうえお', TrimRightChar('あいうえおああいいか', 'かいあ'));
  Check('う', TrimRightChar('う      ', '  '));
  Check('    YY', TrimRightChar('    YY  X', '  X'));
  Check('012', TrimRightChar('012346789', '346789'));
  Check('XXYYZZABC', TrimRightChar('XXYYZZABCXYZ', 'XYZ'));
  Check('', TrimRightChar('XXYYZZABCXYZ', 'XYZABC'));
  Check(#9'AAA', TrimRightChar(#9'AAA'#9, #9));
  Check(#9, TrimRightChar(#9'AAA', 'A'));
  Check(#9'AAA', TrimRightChar(#9'AAA'#13#10, #13#10));
  Check(#13#10, TrimRightChar(#13#10#9'AAA', #9'A'));
  Check('123', TrimRightChar('123', ''));
end;

procedure testTrimChar;
begin
  Check('ABC', TrimChar('123467829ABC5212694192', '0123456789'));
  Check('', TrimChar('123467829ABC5212694192', 'ABC0123456789'));
  Check('かきくけこ', TrimChar('あいうえああいいかきくけこおおえういあい', 'あいうえお'));
  Check('AAA', TrimChar(#9'AAA'#9, #9));
  Check(#9, TrimChar(#9'AAA', 'A'));
  Check(#9'AAA', TrimChar(#9'AAA'#13#10, #13#10));
  Check(#13#10, TrimChar(#9'AAA'#13#10, #9'A'));
  Check('123', TrimChar('123', ''));
end;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加