文字列操作について

解決


Delphi初心者  2005-10-20 08:58:34  No: 18179

簡単な質問だと思いますが、例えば「abcdafff」と文字列があった場合に
文字列を後ろから検索して先頭から2つ目の「a」より後ろの「fff」を
取得する便利な関数はありませんか?
先頭から2つ目の「a」の位置がPos関数等で簡単に取得出来れば良いのですが・・。

また、これに関連して「c」より前の「ab」を取得する関数はありませんか?
Copy関数のように「c」の文字位置より「ab」を取得するのではなく、
「c」という文字を基準にして「ab」を取得することは出来ませんか?

よろしくお願いします。


はいはい  2005-10-20 11:02:56  No: 18180

正規表現ユニット使ってもいいですが、Delphiで書くならこんな漢字。

//1
function getText1(SubStr,Str:string):string;
var i:integer;
begin
for i:= Length(Str)-Length(SubStr) downto 1 do
begin
  if Copy(Str,i,Length(SubStr))=SubStr then
  begin
    Result:=Copy(Str,i+Length(SubStr),Length(Str));
    exit;
  end;
  Result:='';
end;
end;
//日本語サポート版
function getText1W(SubStr,Str:Widestring):WideString;
var i:integer;
begin
for i:= Length(Str)-Length(SubStr) downto 1 do
begin
  if Copy(Str,i,Length(SubStr))=SubStr then
  begin
    Result:=Copy(Str,i+Length(SubStr),Length(Str));
    exit;
  end;
  Result:='';
end;
end;
//2
function getText2(SubStr,Str:string):string;
var i:integer;
begin
for i:= Length(Str)-Length(SubStr) downto 1 do
begin
  if Copy(Str,i,Length(SubStr))=SubStr then
  begin
    Result:=Copy(Str,1,i-1);
    exit;
  end;
  Result:='';
end;
end;
//日本語サポート版
function getText2W(SubStr,Str:string):string;
var i:integer;
begin
for i:= Length(Str)-Length(SubStr) downto 1 do
begin
  if Copy(Str,i,Length(SubStr))=SubStr then
  begin
    Result:=Copy(Str,1,i-1);
    exit;
  end;
  Result:='';
end;
end;

//サンプル
procedure TForm1.Button1Click(Sender: TObject);
begin
  Caption:=getText1('a','abcdafff');
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
  Caption:=getText2('c','abcdafff');
end;


はいはい  2005-10-20 11:04:13  No: 18181

//2
//日本語サポート版
function getText2W(SubStr,Str:Widestring):Widestring;


ハイは一回でヨシ  2005-10-20 19:56:14  No: 18182

> 文字列を後ろから検索して先頭から2つ目の「a」より後ろの「fff」を
> 取得する便利な関数はありませんか?
後ろから検索して、前から二つ目の「a」?
前から検索した方が早いですよ。
後ろから検索して見つかった「a」が、先頭から何番目かなんてわかりませんけど?

> 取得する便利な関数はありませんか?
ありません

> 「c」という文字を基準にして「ab」を取得することは出来ませんか?
できます


ハイは一回でヨシ  2005-10-20 19:57:39  No: 18183

やりたいことがわかっているのだから、その通りにやればいいだけです。

↓ノリで書いたので、コンパイルが通るのかも、動くのかもテストしていません。

function HogeHoge1(aSubStr, aStr: String): String;
var
  i: Integer;
begin
  //例: aSubStr = 'a', aStr := 'abcdafff'
  Result := '';

  //一個目の'a'を検索
  i := Pos(aSubStr, aStr);
  //i:=1
  if i > 0 then begin
    //一個目の'a'までを削除
    //'abcdafff' -> 'bcdafff'
    Delete(aStr, 1, i + Length(aSubStr) - 1);
    //二個目の'a'を検索
    i := Pos(aSubStr, aStr);
    //i=4
    if i > 0 then begin
      //二個目の'a'までを削除
      //'bcdafff' -> 'fff'
      Delete(aStr, 1, i + Length(aSubStr) - 1);
      Result := aStr;
    end;
  end;
end;

function HogeHoge2(aSubStr, aStr: String): String;
var
  i: Integer;
begin
  //例: aSubStr = 'c', aStr := 'abcdafff'
  Result := '';

  //'c'を検索
  i := Pos(aSubStr, aStr);
  //i:=3
  if i > 0 then begin
    //'c'以降を削除
    //'abcdafff' -> 'ab'
    Delete(aStr, i, Length(aStr));
    Result := aStr;
  end;
end;


ハイは一回でヨシ  2005-10-20 19:58:52  No: 18184


はいはい さんとは書き方が違うだけと思うが、詳しく見ていない


はい  2005-10-20 22:54:35  No: 18185

違うでしょ。
「にわ」「にわにはにわにわとりがいる」

「にわとりがいる」と「とりがいる」のどっちが欲しいのか次第。
そもそも”後ろから検索して先頭から2つ目の「a」より後ろの「fff」”が曖昧な表現だから
後ろから検索して最初に見つかった文字の後ろなのか
前から検索して二つ目に見つかった文字の後ろなのか不明。


あいまい  2005-10-20 23:49:34  No: 18186

質問の仕方が論理的にあいまいすぎるだよ。

> 文字列を後ろから検索して先頭から2つ目の「a」より後ろの「fff」を

これは、後ろから検索する意味がない。先頭から検索しないと「2つ目」で
あることが確定しない。

> これに関連して「c」より前の「ab」を取得する関数はありませんか?

これはcより前の半角2文字分なのか、cより前の文字列全部なのかわからない。

ほんとは、こんな自分規格な論理は汎用の関数を組み合わせて自分でつくる
ものなんだよ。

論理を整理すると、Pos() や AnsiPos() のように最初に見つかった位置だけ
じゃなくて2番目以降も調べられる関数をつくれば、あとは簡単。


Delphi初心者  2005-10-21 07:09:35  No: 18187

みなさんレスありがとうございます。
返信が遅くなりすみません。

質問内容があいまいでご迷惑をおかけしました。

> 文字列を後ろから検索して先頭から2つ目の「a」より後ろの「fff」を
これは、文字列を後ろから検索して最初に見つかった「a」より後ろの「fff」をという意味です。
Notesで言うところの、「strRightBack('abcdafff', 'a')」です。

> これはcより前の半角2文字分なのか、cより前の文字列全部なのかわからない。
cより前の文字列全部の意味です。
Notesで言うところの、「strLeft('abcdafff', 'c')」です。

> ほんとは、こんな自分規格な論理は汎用の関数を組み合わせて自分でつくる
> ものなんだよ。
Delphiの標準関数であればと思い質問しましたが、やっぱり自作するしかないんですね。


junki  URL  2005-10-21 07:51:27  No: 18188

面白いのでやってみました。ポインタをつかって検索にはコピーを使わないようにして
なるべく処理速度を上げています。

// 文字列の途中からでも検索できる:戻り値はポインタ
function AnsiStrPosEx(Str,SubStr:PChar; InitPos:Cardinal):PChar;
begin
  result := nil;
  if InitPos > StrLen(Str) then exit;
  result := AnsiStrPos(Str+InitPos,SubStr);
end;

// 文字列の途中からでも検索できる:戻り値は文字インデックス
function AnsiPosEx(const Substr,S:string; InitPos:Cardinal):integer;
var
  ret:PChar;
begin
  ret := AnsiStrPosEx(PChar(S),PChar(Substr),InitPos-1);
  if ret = nil then result := 0 else result := ret-PChar(S)+1;
end;

// 一番最後の部分文字列の位置を返す
function GetLastSubstrPos(const Substr,S:string):integer;
var
  l,p,pre:integer;
begin
  result := 0;
  l := Length(SubStr);
  p := AnsiPosEx(Substr,S,1);
  while (P<>0) do begin
    result := p;
    p := AnsiPosEx(Substr,S,p+l);
  end;
end;

// 一番最後の部分文字列より右側の文字列を返す
function strRightBack(const str, substr: string): string;
var
  p: integer;
begin
  result := '';
  p := GetLastSubstrPos(substr, str);
  if p > 0 then
    result := Copy(str,p+Length(substr),Length(str));
end;

// 最初の部分文字列より左側の文字列を返す
function strLeft(const str, substr: string): string;
var
  p: integer;
begin
  result := '';
  p := AnsiPos(substr, str);
  if p > 0 then
    result := Copy(str, 1, p-1);
end;


Delphi初心者  2005-10-23 01:08:25  No: 18189

みなさんありがとうございます。
色々と方法を教えていただき、とても参考になりました。

ただ、出来たら自作の関数を作ってゴリゴリ書くのではなく、標準関数でかつ1〜2行程度で実現したかったので、私も色々と考えて以下のようにして見ました。処理速度は遅いかもしれませんが・・・。

>文字列を後ろから検索して先頭から2つ目の「a」より後ろの「fff」を
strA := ReverseString('abcdafff');
strA := ReverseString(Copy(strA, 1, Pos('a', strA) - 1));


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

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






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