(*--▽---------------------------▼-- セパレータで文字を分解する処理 00/05/11 00/08/22 実装を丸ごと変更しました。 単語分解方法を幾つか選択出来るようにしたので ExcelのCSVファイルなど読むときも利用できます。 他にもDelimitersを引数指定するようにして使い勝手が上がっています。 00/08/25 Wordxxx2という関数名をWordxxxにしました 01/03/29 タブ文字の対応が出来ていなかったので修正 カンマ文字がDelimitersに含まれていない場合の処理を修正 WordCountとWordGetの内部ルーチンをWordDecomposerとして1つにまとめた 01/10/29 TWordDecomposeを実装 そのために無駄がないように function WordDecomposer に StringListを引数で渡すようにした 02/07/04 TWordDecomposeにIndexOfを実装した 2002/11/07 Split関数をStringUnitLightから移動 Split関数の内部を強化、WordDecomposerの内部処理をすべてまかす 2010/03/03(水) ・ WordDecompose.pasから DelimitedTextUnit.pasと名前変更 ・ TSpliterをTWideStringSpliterとして実装をまとめた ・ WordCount/WordGetのフラグDecomposedModeを TSplitFlagsで置き換えた //--▲---------------------------△--*) unit DelimitedTextUnit; interface uses // Types, SysUtils, StringUnit, // XPtest, uses_end; type TSplitFlags = set of (sfIncludeDelimiter, sfEmptyStr); {↑sfIncludeDelimiter 分割時の戻り値に区切り文字自体も含まれる sfEmptyStr 空文字も分割したとみなす 例えば[A,B,]を分割する時[A][B][空文字]に分解される} const dmUserFriendly: TSplitFlags = []; dmDelimiterExactly: TSplitFlags = [sfEmptyStr]; {単語分解方法 UserFriendlyは区切り文字が複数個でも単語単位に分解 DelimiterExactlyは区切り文字に完全に正確に分解} // TDecomposeMode = (dmUserFriendly, dmDelimiterExactly); function WordCount(const S: WideString; Delimiters: array of WideString; SplitFlag: TSplitFlags): Integer; function WordGet(const S: WideString; Delimiters: array of WideString; WordIndex: Integer; SplitFlag: TSplitFlags): WideString; type TWordDecompose = class(TObject) private FWords: TWideStringDynArray; FSentence: WideString; FDelimiters: TWideStringDynArray; function GetWords(Index: Integer): WideString; function GetCount: Integer; public constructor Create(const Sentence: WideString; Delimiters: array of WideString; Mode: TSplitFlags); destructor Destroy; override; property Words[Index: Integer]: WideString read GetWords; property Count: Integer read GetCount; property Sentence: WideString read FSentence; property Delimiters: TWideStringDynArray read FDelimiters; function IndexOf(const Word: String; IgnoreCase: Boolean): Integer; end; {Create時に単語分解を行ってしまうクラス WordCount/WordGet毎に処理する無駄をはぶく} type TItemAddEvent = procedure(const AddStr: WideString); TWideStringSpliter = class(TObject) private FReturn: TWideStringDynArray; procedure ItemAdd(const AddStr: WideString); public constructor Create(Result: TWideStringDynArray); procedure Split(const Value: WideString; const Delimiters: array of WideString; Flags: TSplitFlags); property Result: TWideStringDynArray read FReturn; end; function Split(const WideStr: WideString; const Delimiters: array of WideString; Flags: TSplitFlags): TWideStringDynArray; overload; //function Split(const WideStr: WideString; const Delimiters: WideString; // Flags: TSplitFlags): TWideStringDynArray; overload; implementation //------------------------------- //単語の数 //Delimitersに[,;:.]と指定すると //それぞれを区切り文字として認識して単語分解が行われる //function WordCount(const S: WideString; Delimiters: array of WideString; // SplitFlag: TSplitFlags): Integer; //var // WordDecompose1: TWordDecompose; //begin // WordDecompose1 := TWordDecompose.Create(S, Delimiters, SplitFlag); // try // Result := WordDecompose1.Count; // finally // WordDecompose1.Free; // end; //end; function WordCount(const S: WideString; Delimiters: array of WideString; SplitFlag: TSplitFlags): Integer; var Spliter: TWideStringSpliter; SplitResult: TWideStringDynArray; begin SetLength(SplitResult, 0); Spliter := TWideStringSpliter.Create(SplitResult); try Spliter.Split(S, Delimiters, SplitFlag); Result := Length(Spliter.Result); finally Spliter.Free; end; end; //------------------------------- //{区切られた単語を番号で呼び出す //Delimitersに[,;:.]と指定すると //それぞれを区切り文字として認識して単語分解が行われる //function WordGet(const S: WideString; Delimiters: array of WideString; // WordIndex: Integer; SplitFlag: TSplitFlags): WideString; //var // WordDecompose1: TWordDecompose; //begin // WordDecompose1 := TWordDecompose.Create(S, Delimiters, SplitFlag); // try // Result := WordDecompose1.Words[WordIndex]; // finally // WordDecompose1.Free; // end; //end; function WordGet(const S: WideString; Delimiters: array of WideString; WordIndex: Integer; SplitFlag: TSplitFlags): WideString; var Spliter: TWideStringSpliter; SplitResult: TWideStringDynArray; begin SetLength(SplitResult, 0); Spliter := TWideStringSpliter.Create(SplitResult); try Spliter.Split(S, Delimiters, SplitFlag); Result := Spliter.Result[WordIndex]; finally Spliter.Free; end; end; { TWordDecompose } constructor TWordDecompose.Create(const Sentence: WideString; Delimiters: array of WideString; Mode: TSplitFlags); var i: Integer; begin FWords := Split(Sentence, Delimiters, Mode); FSentence := Sentence; SetLength(FDelimiters, Length(Delimiters)); for i := 0 to Length(Delimiters)-1 do begin FDelimiters[i] := Delimiters[i]; end; end; destructor TWordDecompose.Destroy; begin inherited; end; function TWordDecompose.GetCount: Integer; begin Result := Length(FWords); end; function TWordDecompose.GetWords(Index: Integer): WideString; begin if ( 0 <= Index ) and ( Index <= (Length(FWords)-1) ) then begin Result := FWords[Index]; end else begin Result := ''; end; end; function TWordDecompose.IndexOf(const Word: String; IgnoreCase: Boolean): Integer; var i: Integer; CompareFunction: function(const S1, S2: string): Boolean; begin Result := -1; for i := 0 to Length(FWords)-1 do begin if (IgnoreCase=True) then begin CompareFunction := AnsiSameText; end else begin CompareFunction := AnsiSameStr; end; if CompareFunction(FWords[i], Word) then begin Result := i; Exit; end; end; end; {------------------------------- // 文字列を区切り文字で分解して 文字列動的配列として戻す関数 引数説明: WideStr:区切らせたい文字列 Delimiter:区切り文字の動的配列 ItemAddDelimiter:戻す配列内に区切り文字も含めるかどうかのフラグ ItemAddEmptyStr:戻す配列内に空文字列も入れるかどうかのフラグ 戻り値: WideStringの動的配列 備考: C#にあるのでDelphiでも実装してみた 部分文字列比較にWideStringPartsCompare関数を使っている 履歴: 2002/09/27 作成 2002/10/02 ItemAddDelimiterフラグを追加 2002/11/07 ItemAddEmptyStrフラグを追加 //--▼----------------------▽--} { TWideStringSpliter } constructor TWideStringSpliter.Create(Result: TWideStringDynArray); begin FReturn := Result; end; procedure TWideStringSpliter.ItemAdd(const AddStr: WideString); begin SetLength(FReturn, Length(FReturn)+1); FReturn[Length(FReturn)-1] := AddStr; end; //procedure TWideStringSpliter.Split(const Value: WideString; // const Delimiters: array of WideString; Flags: TSplitFlags); // // { --▽---------------------------▼-- // TWideStringDynArrayのIndexOf // ただし、WideStrのIndexから始まる部分の文字列との一致を比較する // //--▲---------------------------△-- } // function WideStrArrayIndexOf(const Str: WideString; Index: Integer; // SubStrs: array of WideString): Integer; // var // i: Integer; // begin // Result := -1; // for i := 0 to Length(SubStrs)-1 do // begin // if WideStringPartsCompare(SubStrs[i], Str, Index) then // begin // Result := i; // exit; // end; // end; // end; // //var // i, j, ArrayIndex: Integer; // Buffer: WideString; // BufferLen: Cardinal; //begin // BufferLen := 0; // SetLength(Buffer, Length(Value)); // // i := 1; while i <= Length(Value) do // begin // ArrayIndex := WideStrArrayIndexOf(Value, i, Delimiters); // {↓WideStrのi番目の文字がデリミタじゃない場合} // if ArrayIndex = -1 then // begin // Inc(BufferLen); // Buffer[BufferLen] := Value[i]; // Inc(i); // end else // {↓WideStrのi番目の文字がデリミタの場合} // begin // if (1 <= BufferLen) or (sfEmptyStr in Flags) then // begin // SetLength(Buffer, BufferLen); // ItemAdd(Buffer); // BufferLen := 0; // SetLength(Buffer, Length(Value)); // end; // // if sfIncludeDelimiter in Flags then // begin // for j := 1 to Length(Delimiters[ArrayIndex]) do // begin // Inc(BufferLen); // Buffer[BufferLen] := Delimiters[ArrayIndex][j]; // end; // // if (1 <= BufferLen) then // begin // SetLength(Buffer, BufferLen); // ItemAdd(Buffer); // BufferLen := 0; // SetLength(Buffer, Length(Value)); // end; // end; // // Inc(i, Length(Delimiters[ArrayIndex])); // end; // end; // // if (1<=BufferLen) or (sfEmptyStr in Flags) then // begin // SetLength(Buffer, BufferLen); // ItemAdd(Buffer); // end; //end; procedure TWideStringSpliter.Split(const Value: WideString; const Delimiters: array of WideString; Flags: TSplitFlags); { --▽---------------------------▼-- TWideStringDynArrayのIndexOf ただし、WideStrのIndexから始まる部分の文字列との一致を比較する //--▲---------------------------△-- } function WideStrArrayIndexOf(const Str: WideString; Index: Integer; SubStrs: array of WideString): Integer; var i: Integer; begin Result := -1; for i := 0 to Length(SubStrs)-1 do begin if WideStringPartsCompare(SubStrs[i], Str, Index) then begin Result := i; exit; end; end; end; var i, j, Len, ArrayIndex: Integer; Buffer: WideString; BufferLen: Integer; begin SetLength(FReturn, 0); // if Value = EmptyStr then // begin // Exit; // end; Len := Length(Value); BufferLen := 0; SetLength(Buffer, Length(Value)); i := 1; while i <= Length(Value) do begin ArrayIndex := WideStrArrayIndexOf(Value, i, Delimiters); {↓WideStrのi番目の文字がデリミタじゃない場合} if ArrayIndex = -1 then begin Inc(BufferLen); Buffer[BufferLen] := Value[i]; Inc(i); end else {↓WideStrのi番目の文字がデリミタの場合} begin if (1 <= BufferLen) or (sfEmptyStr in Flags) then begin SetLength(Buffer, BufferLen); ItemAdd(Buffer); BufferLen := 0; SetLength(Buffer, Length(Value)); end; if sfIncludeDelimiter in Flags then begin for j := 1 to Length(Delimiters[ArrayIndex]) do begin Inc(BufferLen); Buffer[BufferLen] := Delimiters[ArrayIndex][j]; end; if (1 <= BufferLen) then begin SetLength(Buffer, BufferLen); ItemAdd(Buffer); BufferLen := 0; SetLength(Buffer, Length(Value)); end; end; Inc(i, Length(Delimiters[ArrayIndex])); end; end; if (1<=BufferLen) or (sfEmptyStr in Flags) then begin SetLength(Buffer, BufferLen); ItemAdd(Buffer); end; end; function Split(const WideStr: WideString; const Delimiters: array of WideString; Flags: TSplitFlags): TWideStringDynArray; var Spliter: TWideStringSpliter; begin SetLength(Result, 0); Spliter := TWideStringSpliter.Create(Result); try Spliter.Split(WideStr, Delimiters, Flags); Result := Spliter.Result; finally Spliter.Free; end; end; //--△----------------------▲-- end.