DelFusa Blog 総本山

プログラミングの話題とかです。

NEW | PAGE-SELECT | NEXT

≫ EDIT

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

| スポンサー広告 | --:-- | comments(-) | trackbacks(-) | TOP↑

≫ EDIT

文字列から数値表現を抽出


♪   ∧,,∧ ♪
    ミ,,゚Д゚彡  ♪
    ミつ[|lllll]).
   ~ミ   ミ
     ∪''∪
自分のトコだけど、間借りします



くだすれDelphi(超初心者用)その41
http://pc11.2ch.net/test/read.cgi/tech/1176867736/
ここで会話している>>546時点での、カキコです。

何をする関数なのかっていうと

『ABC123DEF-456GHI2007/05/11 17:12JKL』という文字列から
123
-456
2007
5
11
17
12
という数値を切り出す処理。
以下、ソース。


//文字列から数値を切り出す処理
//数値文字列内の+-の記号後にスペースやタブが存在しても無視するようにする数値中に1回のカンマがあっても無視する
function PickOutInt64FromStringVer3(Source: WideString): TInt64DynArray;
type
 TPaserStatus = (psNormal, psPerhapsNumeric, psNumeric);
const
 NumericCharTable: WideString = '01234567890123456789';
 PlusMinusSignTable: WideString = '+-+-';
 CommaSignTable: WideString = ',,';
 BypassSignTable: WideString = '  '+TAB;
var
 i: Integer;
 NumericOutput: WideString;
 PaserStatus: TPaserStatus;
  {↓バッファに数値文字列が入っているなら
    動的配列に追加して出力する関数}
  procedure StrOutputNumeric;
  var
   OutputValue: Int64;
  begin
   if NumericOutput = '' then Exit;
   if TryStrToInt64(ZenkakuToHankaku(NumericOutput), OutputValue) then
   begin {↑確保している値がInt64に変更出来るなら}
    {↓数値を動的配列に追加する}
    SetLength(Result, Length(Result)+1);
    Result[Length(Result)-1] := OutputValue;
   end;
   NumericOutput := '';
  end;

  function GetIndexChar(Source: WideString; Index: Integer): WideChar;
  begin
   if (Index <= 0) or (Length(Source) < Index) then
   begin
    Result := NULLSTR;
   end else
   begin
    Result := Source[Index];
   end;
  end;

begin
 PaserStatus := psNormal;
 SetLength(Result, 0);

 for i := 1 to Length(Source) do
 begin
  case PaserStatus of
   psNormal: {←普通の文字列状態で}
   begin
    if (CheckWideCharInTable(GetIndexChar(Source, i), NumericCharTable)) then
    begin {↓数値の場合}
     PaserStatus := psNumeric;
     NumericOutput := GetIndexChar(Source, i);
    end else
    if CheckWideCharInTable(GetIndexChar(Source, i), PlusMinusSignTable) then
    begin {↓+-記号の場合}
     PaserStatus := psPerhapsNumeric;
     NumericOutput := GetIndexChar(Source, i);
    end;
   end;
   psPerhapsNumeric: {←数値かもしれない状態で}
   begin
    if CheckWideCharInTable(GetIndexChar(Source, i), PlusMinusSignTable) then
    begin {↓+-記号の場合}
     {↓数値じゃなかったということでバッファを戻す}
     NumericOutput := GetIndexChar(Source, i);
    end else
    if CheckWideCharInTable(GetIndexChar(Source, i), BypassSignTable) then
    begin {↓スペースなどの場合}
     continue; {←無視する}
    end else
    if (CheckWideCharInTable(GetIndexChar(Source, i), NumericCharTable)) then
    begin {↓数値の場合}
     PaserStatus := psNumeric;
     NumericOutput := NumericOutput + GetIndexChar(Source, i);
    end else
    begin {↓それ以外の場合}
     PaserStatus := psNormal; {状態をキャンセルしてノーマル状態にする}
     NumericOutput := '';
    end;
   end;
   psNumeric: {←数値の状態で}
   begin
    if (CheckWideCharInTable(GetIndexChar(Source, i), NumericCharTable)) then
    begin {↓数値の場合}
     NumericOutput := NumericOutput + GetIndexChar(Source, i);
    end else
    if (CheckWideCharInTable(GetIndexChar(Source, i), CommaSignTable)) then
    begin {↓Commaの場合}
     {↓Commaの前が数値じゃなければ}
     if not CheckWideCharInTable(GetIndexChar(Source, i-1), NumericCharTable) then
     begin {↓状態キャンセル}
      PaserStatus := psNormal;
      StrOutputNumeric;
     end;
     continue; {←無視する}
    end else
    begin
     PaserStatus := psNormal;
     StrOutputNumeric;
    end;
   end;
  end;
 end;
 {↓ループ最後に行う出力処理}
 StrOutputNumeric;
end;

function PickOutInt64FromString3(Source: WideString): Int64;
var
 Int64Array: TInt64DynArray;
begin
 Result := 0;
 Int64Array := PickOutInt64FromStringVer3(Source);
 if 1 <= Length(Int64Array) then
 begin
  Result := Int64Array[0];
 end;
end;

 Check(True, 32 = PickOutInt64FromString3('ABC 32 DEF'));
 Check(True, 32 = PickOutInt64FromString3('ABC ,32 DEF'));
 Check(True, 32 = PickOutInt64FromString3('ABC 3,2 DEF'));
 Check(True, 32 = PickOutInt64FromString3('ABC 32, DEF'));
 Check(True, 3 = PickOutInt64FromString3('ABC 3, 2 DEF'));
 Check(True, 3 = PickOutInt64FromString3('ABC 3 2 DEF'));
 Check(True, 3200 = PickOutInt64FromString3('ABC 3200 DEF'));
 Check(True, 3200 = PickOutInt64FromString3('ABC 32,00 DEF'));
 Check(True, 3200 = PickOutInt64FromString3('ABC 3,200 DEF'));
 Check(True, 3 = PickOutInt64FromString3('ABC 3,,200 DEF'));
 Check(True, 3 = PickOutInt64FromString3('ABC 3 ,200 DEF'));
 Check(True, 320 = PickOutInt64FromString3('ABC 320, 0 DEF'));
 Check(True, 320 = PickOutInt64FromString3('ABC + 320, 0 DEF'));
 Check(True, -3200 = PickOutInt64FromString3('ABC - 3200 DEF'));
 Check(True, 320 = PickOutInt64FromString3('ABC 320,,0 DEF'));
 Check(False, 122 = PickOutInt64FromString3('123DEF456'));
 Check(True, 123 = PickOutInt64FromString3('123,DEF,456'));
 Check(True, 123 = PickOutInt64FromString3('+,123DEF456'));
 Check(True, 123 = PickOutInt64FromString3('-,123DEF456'));
 Check(True, -123 = PickOutInt64FromString3(',-123DEF456'));
 Check(True, -123 = PickOutInt64FromString3(',-12,3DEF456'));
 Check(True, 32 = PickOutInt64FromString3('ABC +32 DEF'));
 Check(True, -3200 = PickOutInt64FromString3('ABC -3200 DEF'));
 Check(True, 3200 = PickOutInt64FromString3('ABC -,3200 DEF'));
 Check(True, -3200 = PickOutInt64FromString3('ABC -3,200 DEF'));

 Check(True, 32 = PickOutInt64FromString3('ABC 32 DEF'));
 Check(True, 32 = PickOutInt64FromString3('ABC ,32 DEF'));
 Check(True, 32 = PickOutInt64FromString3('ABC 3,2 DEF'));
 Check(True, 32 = PickOutInt64FromString3('ABC 32, DEF'));
 Check(True, 3 = PickOutInt64FromString3('ABC 3, 2 DEF'));
 Check(True, 3 = PickOutInt64FromString3('ABC 3 2 DEF'));
 Check(True, 3200 = PickOutInt64FromString3('ABC 3200 DEF'));
 Check(True, 3200 = PickOutInt64FromString3('ABC 32,00 DEF'));
 Check(True, 3200 = PickOutInt64FromString3('ABC 3,200 DEF'));
 Check(True, 3 = PickOutInt64FromString3('ABC 3,,200 DEF'));
 Check(True, 3 = PickOutInt64FromString3('ABC 3 ,200 DEF'));
 Check(True, 320 = PickOutInt64FromString3('ABC 320, 0 DEF'));
 Check(True, 320 = PickOutInt64FromString3('ABC + 320, 0 DEF'));
 Check(True, -3200 = PickOutInt64FromString3('ABC - 3200 DEF'));
 Check(True, 320 = PickOutInt64FromString3('ABC 320,,0 DEF'));
 Check(False, 122 = PickOutInt64FromString3('123DEF456'));
 Check(True, 123 = PickOutInt64FromString3('123,DEF,456'));
 Check(True, 123 = PickOutInt64FromString3('+,123DEF456'));
 Check(True, 123 = PickOutInt64FromString3('-,123DEF456'));
 Check(True, -123 = PickOutInt64FromString3(',-123DEF456'));
 Check(True, -123 = PickOutInt64FromString3(',-12,3DEF456'));
 Check(True, 32 = PickOutInt64FromString3('ABC +32 DEF'));
 Check(True, -3200 = PickOutInt64FromString3('ABC -3200 DEF'));
 Check(True, 3200 = PickOutInt64FromString3('ABC -,3200 DEF'));
 Check(True, -3200 = PickOutInt64FromString3('ABC -3,200 DEF'));
スポンサーサイト

| 未分類 | 17:25 | comments:2 | trackbacks:0 | TOP↑

COMMENT

同じ結果になるように調整したので見てね

| | 2007/05/11 21:20 | URL |

まだ、確認してませんが、
漏れのコードをあっさり理解できるところが、すげーですね。

文字列解析、面白いですね。HTML(orXML)から、『タグを除去』『タグだけ残す』『対応するタグまで選択』などなど、もやってみたいのでいい足がかりになりました。ありがとう。m(._.)m ペコッ

比較ロジックは、こんな感じで実装してみますた。これは単純。

自作の、WideStringRecordListという、StringListのWideString版のSortメソッドを利用してます。

{昇順 1.2.10.20...}
function NumericSortAscending(Item1, Item2: Pointer): Integer;
var
 IntArray1, IntArray2: TInt64DynArray;
 i: Integer;
begin
 {↓文字列から数値を切り出す}
 IntArray1 := PickOutInt64FromStringVer3(TRecord(Item1^));
 IntArray2 := PickOutInt64FromStringVer3(TRecord(Item2^));

 {↓要素毎に数値の大小を比較}
 for i := 0 to Min(Length(IntArray1), Length(IntArray2))-1 do
 begin
  if IntArray1[i] < IntArray2[i] then
  begin
   Result := -1;
   Exit;
  end else
  if IntArray2[i] < IntArray1[i] then
  begin
   Result := 1;
   Exit;
  end else
  begin
   Result := 0;
  end;
 end;

 {↓要素の数値大小で区別がつかなければ要素数で比較}
 if Length(IntArray1) < Length(IntArray2) then
 begin
  Result := -1;
  Exit;
 end else
 if Length(IntArray2) < Length(IntArray1) then
  begin
  Result := 1;
  Exit;
 end else
 begin
  {↓それでも区別つかなければ通常のソートにゆだねる}
  Result := SortAscending(Item1, Item2);
 end;
end;

{降順 20.10.2.1...}
function NumericSortDescending(Item1, Item2: Pointer): Integer;
begin
 Result := -1 * NumericSortAscending(Item1, Item2);
end;

| ミ・д・彡 | 2007/05/12 00:08 | URL |















非公開コメント

TRACKBACK URL

http://delfusa.blog65.fc2.com/tb.php/49-09e65cff

TRACKBACK

PREV | PAGE-SELECT | NEXT

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。