unit mPegFilter;

interface

uses
  Classes, SysUtils;

type
  TPegFilter = class
  private
    FBeginPeg: string;
    FBeginPegNum: Double;
    FEndPeg: string;
    FEndPegNum: Double;

    function PegFormat(const AStr: string): string;
    function FilterPeg(const AStr: string; var APeg: string; var ANum: Double; var ABegin, AEnd: Integer): Boolean;
  public
    function Filter(const AStr: string): Boolean;

    property BeginPeg: string read FBeginPeg;
    property BeginPegNum: Double read FBeginPegNum;
    property EndPeg: string read FEndPeg;
    property EndPegNum: Double read FEndPegNum;
  end;

function PegFilter: TPegFilter;

implementation

uses Math;

var
  FPegFilter: TPegFilter;

function PegFilter: TPegFilter;
begin
  if FPegFilter = nil then
    FPegFilter := TPegFilter.Create;
  Result := FPegFilter;
end;

{ TPegFilter }

function TPegFilter.Filter(const AStr: string): Boolean;
var
  sPeg: string;
  iPos, iBegin, iEnd: Integer;
begin
  sPeg := PegFormat(AStr);
  Result := FilterPeg(sPeg, FBeginPeg, FBeginPegNum, iBegin, iEnd);
  if Result and (sPeg[iEnd+1] = '~') then
  begin
    sPeg := StringReplace(sPeg, FBeginPeg, '', []);
    FilterPeg(sPeg, FEndPeg, FEndPegNum, iBegin, iEnd);
    if FEndPegNum = 0 then
    begin
      FEndPeg := FBeginPeg;
      FEndPegNum := FBeginPegNum;
    end
    else
      Result := FEndPegNum >= FBeginPegNum;
  end
  else
  begin
    FEndPeg := '';
    FEndPegNum := 0;
  end;
end;

function TPegFilter.FilterPeg(const AStr: string; var APeg: string;
  var ANum: Double; var ABegin, AEnd: Integer): Boolean;

  function FilterInt(ABegin: Integer; var AEnd: Integer; var AIntStr: string; var AValue: Integer): Boolean;
  var
    iPos, iLength: Integer;
    sInt: string;
  begin
    AIntStr := '';
    AEnd := ABegin;

    iPos := ABegin;
    iLength := Length(AStr);
    while (iPos <= iLength) do
    begin
      if AStr[iPos] in ['0'..'9'] then
      begin
        AIntStr := AIntStr + AStr[iPos];
        AEnd := iPos;
      end
      else Break;
      Inc(iPos);
    end;

    Result := AIntStr <> '';
    AValue := StrToIntDef(AIntStr, 0);
  end;

  // 过滤一个小于1000的Float
  function FilterFloat(ABegin: Integer; var AEnd: Integer; var AFloatStr: string; var AValue: Double): Boolean;
  var
    iPos, iLength, iIntPartLength: Integer;
    bHasPoint, bAllZero: Boolean;
  begin
    AFloatStr := '';
    AEnd := ABegin;

    iPos := ABegin;
    iLength := Length(AStr);
    bHasPoint := False;
    bAllZero := True;
    iIntPartLength := 0;
    while (iPos <= iLength) do
    begin
      if AStr[iPos] in ['0'..'9'] then
      begin
        AFloatStr := AFloatStr + AStr[iPos];
        AEnd := iPos;
        if not bHasPoint then
          Inc(iIntPartLength);

        bAllZero := bAllZero and (AStr[iPos] = '0');
      end
      else if (AStr[iPos] = '.') and (not bHasPoint) then
      begin
        AFloatStr := AFloatStr + AStr[iPos];
        AEnd := iPos;
        bHasPoint := True;
      end
      else Break;
      Inc(iPos);
    end;

    if iIntPartLength > 3 then
    begin
      AEnd := ABegin + 3 - 1;
      AFloatStr := Copy(AFloatStr, 1, 3);
    end;

    AValue := StrToFloatDef(AFloatStr, 0);
    Result := (AValue <> 0) or (bAllZero and (AEnd > ABegin));
  end;

var
  iPos, iLength: Integer;
  iBeginNum, iEndNum, iPosPuls, iBeginNum2, iEndNum2: Integer;
  sNum, sNum2: string;
  iNum: Integer;
  fNum: Double;
begin
  Result := False;
  APeg := '';
  ANum := 0;
  ABegin := -1;
  AEnd := -1;

  iPos := 1;
  iLength := Length(AStr);
  while (iPos <= iLength) and (not Result) do
  begin
    if AStr[iPos] = 'k' then
    begin
      iBeginNum := iPos + 1;
      if FilterInt(iBeginNum, iEndNum, sNum, iNum) then
      begin
        iPosPuls := iEndNum + 1;
        if AStr[iPosPuls] = '+' then
        begin
          iBeginNum2 := iPosPuls + 1;
          if FilterFloat(iBeginNum2, iEndNum2, sNum2, fNum) then
          begin
            Result := True;
            APeg := Copy(AStr, iPos, iEndNum2-iPos+1);
            ANum := iNum * 1000 + fNum;
            ABegin := iPos;
            AEnd := iEndNum2;
          end;
        end;
      end
    end;
    inc(iPos);
  end;
end;

function TPegFilter.PegFormat(const AStr: string): string;
begin
  Result := AStr;
  Result := StringReplace(Result, 'K', 'k', [rfReplaceAll]);
  Result := StringReplace(Result, '＋', '+', [rfReplaceAll]);
  Result := StringReplace(Result, '～', '~', [rfReplaceAll]);
  Result := StringReplace(Result, ' ', '', [rfReplaceAll]);
end;

initialization
  FPegFilter := nil;
finalization
  FPegFilter.Free;
end.
