文字列内の部分文字列が単語かどうかをチェックする
文字列内から単語を検索する際に、検索した部分文字列が単語かどうかを全角文字を考慮して判断するユニットです。文字列が半角英数字のみであれば、検索した部分文字列の前後がホワイトスペース,もしくは記号かどうかをチェックするだけで済みますが、「今日はパソコンを使わなかった」等の全角文字が含まれる文字列から「パソコン」を単語として認識させるためには、前後文字の種類も判別しないといけません。
以下のユニットでは検索した部分文字列が全角文字の場合には、その種類(ひらがな,カタカナ,漢字,英数字)もチェックして、前後の文字種が同じかどうかを調べることで、ある程度の全角単語を認識させることが出来ます(ある程度と言うのは、検索語がひらがなのみ,カタカナのみ等の場合にのみ単語として認識することが可能という意味です)。
以下のソースをファイル名「IsWholeWd.pas」として保存して下さい。使用する場合にはuses節にIsWholeWdを追加するだけです。
(*
IsWholeWdユニット
文字列中の指定した語句が単語かどうかをチェックする
使用例)
FoundAt := AnsiPos(FindStr, Str);
if (FoundAt > 0) and IsWholeWord(Str, FoundAt, Length(FindStr) then
見つけた処理...
前後の区切り子を確認することで検索した語句が単語かどうかを判断する
全角文字の場合には、前後の文字が漢字,ひらがな,カタカナ,英字
の違いもチェックすることで、"ある程度"の単語判断が可能
Copyright(c) 2001 M&I
mailto:masahiro.inoue@nifty.ne.jp
http://member.nifty.ne.jp/m-and-i/
*)
unit IsWholeWd;
interface
function IsWholeWord(const S: string; const StartPos, FindLen: integer): Boolean;
implementation
uses SysUtils;
const
// 半角区切り子
ANKSEP = #9#10#13' !"#$%&''()=~^\|{}[]`@;+:*,<.>/?';
// 全角区切り子
ZENSEP = ' 、。,.・:;?!゛゜´`¨^ ̄_〇ー―‐/\〜‖|…‥'+
'‘’“”()〔〕[]{}〈〉《》「」『』【】+−±×÷=≠'+
'<>≦≧∞∴♂♀°′″℃¥$¢£%#&*@§☆★○●◎◇◆'+
'□■△▲▽';
// S: 文字列全体
// StartPos: 検索された位置
// FindLen: 検索された長さ
// Result: 単語ならTrue
function IsWholeWord(const S: string; const StartPos, FindLen: integer): Boolean;
var
sr, er,
knj, knjh, knjk,
knja, knjz,
ank, kana: Boolean;
cc, ks, ke,
EndPos: integer;
// 速度を考えるとCのようにマクロで展開したいところ...
function IsKanji(const ch: Char): Boolean;
begin
Result := Ord(Ch) > $7F;
end;
function IsKanji2(const ch: Char): Boolean;
var
c: Byte;
begin
c := Ord(ch);
Result := (c in [$40..$7E]) or (c in [$80..$FC]);
end;
function IsKana(const ch: Char): Boolean;
begin
Result := Ord(ch) in [$A1..$DF];
end;
function isZHira(Ch: integer): Boolean;
begin
Result := (Ch >= $829F) and (Ch <= $82F1);
end;
function isZKana(Ch: integer): Boolean;
begin
Result := (Ch >= $8340) and (Ch <= $8396);
end;
function isZAnk(Ch: integer): Boolean;
begin
Result := (Ch >= $824F) and (Ch <= $829A);
end;
function isZKnj(Ch: integer): Boolean;
begin
Result := Ch >= $889F;
end;
begin
if S = '' then
begin
Result := False;
Exit;
end;
EndPos := StartPos + FindLen - 1;
sr := StartPos = 1;
er := EndPos = Length(S);
// 行にこの単語しかない
if sr and er then
begin
Result := True;
Exit;
end;
knj := False;
knjk := False;
knjh := False;
knja := False;
knjz := False;
kana := False;
ank := False;
cc := EndPos - StartPos;
// 検索語が1文字以上の場合文字の種類をチェックする
if cc > 0 then
begin
// 最初と最後が漢字
if IsKanji(S[StartPos]) and IsKanji2(S[StartPos+1]) then
begin
if IsKanji(S[EndPos-1]) and IsKanji2(S[EndPos]) then
knj := True;
end else if IsKana(S[StartPos]) and Iskana(S[EndPos]) then
kana := True
else if (Ord(S[StartPos]) < $80) and (Ord(S[EndPos]) < $80) then
ank := True;
end else begin
if IsKana(S[StartPos]) then
kana := True
else if Ord(S[StartPos]) < $80 then
ank := True;
end;
//全角の種類を確認する
if knj then
begin
ks := Ord(S[StartPos]) shl 8 + Ord(S[StartPos+1]);
ke := Ord(S[EndPos-1]) shl 8 + Ord(S[EndPos]);
//全角カナ
if IsZKana(ks) and IsZKana(ke) then
knjk := True
//全角ひらがな
else if IsZHira(ks) and IsZHira(ke) then
knjh := True
//全角英数字
else if IsZAnk(ks) and IsZAnk(ke) then
knja := True
//漢字
else if IsZKnj(ks) and IsZKnj(ke) then
knjz := True;
end;
// 検索語が半角英数字
// 前後が半角英数字以外もしくはセパレータ文字かどうかを確認
if ank then
begin
if not sr then
begin
// 前が半角カタカナ
if Iskana(S[StartPos-1]) then
begin
sr := True;
// 前が全角
end else if StartPos > 2 then
begin
if IsKanji(S[StartPos-2]) and IsKanji2(S[StartPos-1]) then
sr := True
else
sr := AnsiPos(S[StartPos-1], ANKSEP) > 0;
end else begin
sr := AnsiPos(S[StartPos-1], ANKSEP) > 0;
end;
end;
if not er then
begin
// 後が半角カタカナ
if Iskana(S[StartPos+1]) then
begin
er := True;
// 後が全角
end else if EndPos < (Length(S) - 1) then
begin
if IsKanji(S[EndPos+1]) and IsKanji2(S[EndPos+2]) then
er := True
else
er := AnsiPos(S[EndPos+1], ANKSEP) > 0;
end else begin
er := AnsiPos(S[EndPos+1], ANKSEP) > 0;
end;
end;
//検索語が半角カタカナ
//前後が半角英数字,全角,セパレータかどうかを確認
end else if kana then
begin
if not sr then
begin
// 前が半角
if Ord(S[StartPos-1]) < $80 then
begin
sr := True;
// 前が全角
end else if StartPos > 2 then
begin
if IsKanji(S[StartPos-2]) and IsKanji2(S[StartPos-1]) then
sr := True;
end else begin
sr := AnsiPos(S[StartPos-1], ANKSEP) > 0;
end;
end;
if not er then
begin
// 後が半角
if Ord(S[StartPos+1]) < $80 then
begin
er := True;
// 後が全角
end else if EndPos < (Length(S) - 1) then
begin
if IsKanji(S[EndPos+1]) and IsKanji2(S[EndPos+2]) then
er := True;
end else begin
er := AnsiPos(S[EndPos+1], ANKSEP) > 0;
end;
end;
//検索語が全角文字
end else if knj then
begin
// 前をチェック
if StartPos > 2 then
begin
//前も漢字か
if IsKanji(S[StartPos-2]) then
begin
//ひらがな,カナ,英数字のチェック
//漢字
if knjz then
begin
if not IsZKnj(Ord(S[StartPos -2]) shl 8 + Ord(S[StartPos-1])) then
sr := True;
//全角カタカナ
end else if knjk then
begin
if not IsZKana(Ord(S[StartPos -2]) shl 8 + Ord(S[StartPos-1])) then
sr := True;
//全角ひらがな
end else if knjh then
begin
if not IsZHira(Ord(S[StartPos -2]) shl 8 + Ord(S[StartPos-1])) then
sr := True;
//全角英数字
end else if knja then
begin
if not IsZAnk(Ord(S[StartPos -2]) shl 8 + Ord(S[StartPos-1])) then
sr := True;
//全角カタカナ
end else begin
if AnsiPos(S[StartPos - 2] + S[StartPos - 1], ZENSEP) > 0 then
sr := True
else
sr := False;
end;
end else
sr := True;
// 前に1文字しかないので全角ではない
end else
sr := True;
// 後をチェック
if EndPos < (Length(S) - 1) then
begin
//後も漢字か
if IsKanji(S[EndPos+1]) then
begin
//ひらがな,カナ,英数字のチェック
if knjz then
begin
if not IsZKnj(Ord(S[EndPos+1]) shl 8 + Ord(S[EndPos+2])) then
er := True;
end else if knjk then
begin
if not IsZKana(Ord(S[EndPos+1]) shl 8 + Ord(S[EndPos+2])) then
er := True;
end else if knjh then
begin
if not IsZHira(Ord(S[EndPos+1]) shl 8 + Ord(S[EndPos+2])) then
er := True;
end else if knja then
begin
if not IsZAnk(Ord(S[EndPos+1]) shl 8 + Ord(S[EndPos+2])) then
er := True;
end else begin
if AnsiPos(S[EndPos + 1] + S[EndPos + 2], ZENSEP) > 0 then
er := True
else
er := False;
end;
end else
er := True;
end else
er := True;
//その他(最初と最後の文字種が違う場合)
//前後が半角と全角のセパレータかどうかを確認
end else begin
if not sr then
begin
if AnsiPos(S[StartPos-1], ANKSEP) > 0 then
begin
sr := True;
end else if StartPos > 2 then
begin
if AnsiPos(S[StartPos - 2] + S[StartPos - 1], ZENSEP) > 0 then
sr := True;
end;
end;
if not er then
begin
if AnsiPos(S[EndPos + 1], ANKSEP) > 0 then
begin
er := True;
end else if Length(S) - 1 > EndPos then
begin
if AnsiPos(S[EndPos + 1] + S[EndPos + 2], ZENSEP) > 0 then
er := True;
end;
end;
end;
//前と後ろ両方がセパレータならワードと見なす
Result := sr and er;
end;
end.