Парсинг строк

Материал из DRKB

Парсинг строк[править | править код]

unit splitfns;

interface
uses Classes, Sysutils;

{ Returns the next token (substring) from string S, starting at index StartPos and ending 1 character
  before the next occurrence of Separator (or at the end of S, whichever comes first).
  StartPos - returns the starting position for the next token, 1 more than the position in S of
  the end of this token }
function GetNextToken(Const S: string; Separator: TSysCharSet; var StartPos: integer): String;

{ Splits a string containing designated separators into tokens and adds them to MyStringList NOTE: MyStringList must be Created before being passed to this procedure and Freed after use }
procedure Split(const S: String; Separator: TSysCharSet; MyStringList: TStringList);

{ Used to join 2 strings with a separator character between them and can be used in a Join function
  The StringLimit parameter prevents the length of the Result String from exceeding a preset maximum }
function AddToken (const aToken, S: String; Separator: Char; StringLimit: integer): String;

implementation

function GetNextToken(Const S: string; Separator: TSysCharSet; var StartPos: integer): String;
var
  Index: integer;
begin
  Result := '';
  { Step over repeated separators }
  while (S[StartPos] in Separator) and (StartPos <= Length(S)) do
    StartPos := StartPos + 1;

  if StartPos > length(S) then Exit;

  { Set Index to StartPos }
  Index := StartPos;

  { Find the next Separator }
  while not (S[Index] in Separator) and (Index <= Length(S)) do
    Index := Index + 1;

  { Copy the token to the Result }
  Result := Copy(S, StartPos, Index - StartPos);

  { SetStartPos to next Character after the Separator }
  StartPos := Index + 1;
end;

procedure Split(const S: String; Separator: TSysCharSet; MyStringList: TStringList);
var
  Start: integer;
begin
   Start := 1;
   while Start <= Length(S) do
     MyStringList.Add(GetNextToken(S, Separator, Start));
end;

function AddToken(const aToken, S: String; Separator: Char; StringLimit: integer): String;
begin
  if Length(aToken) + Length(S) < StringLimit then
  begin
    { Add a separator unless the Result string is empty }
    if S = '' then Result := '' else Result := S + Separator;
    { Add the token }
    Result := Result + aToken;
  end
  else
  { if the StringLimit would be exceeded, raise an exception }
    Raise Exception.Create('Cannot add token');
end;

end.

пример использования:

  data := TStringList.Create();
  splited := TStringList.Create();
  data.LoadFromFile(s);
  Split(data.Text, [',', ' ', #10, #13, ';', '\"', '.', '!', '-', '+', '*', '/', '\',
    '(', ')', '[', ']', '{', '}', '<', '>', '''', '"', '?', '"', '#', #0], splited);
  for i:= 0 to splited.Count-1 do
  begin
    if not words.Find(splited.Strings,adr) then
      words.Add(splited.Strings[i]);
    Application.ProcessMessages(); // make program to respond to user 
      // commands while processing in case of very long string.
  end;


Author: Song
Source: Взято из http://forum.sources.ru
ID: 00150


Некоторое время назад одна любезная душа прислала мне этот модуль. Я нашел его весьма полезным, но применять его вам надлежит с некоторой долей осторожности, ибо тэг %s иногда приводит к исключительным ситуациям.

unit Scanf;

interface
uses SysUtils;

type

  EFormatError = class(ExCeption);

function Sscanf(const s: string; const fmt: string;
  const Pointers: array of Pointer): Integer;
implementation

{ Sscanf выполняет синтаксический разбор входной строки. Параметры...

s - входная строка для разбора
fmt - 'C' scanf-форматоподобная строка для управления разбором
%d - преобразование в Long Integer
%f - преобразование в Extended Float
%s - преобразование в строку (ограничено пробелами)
другой символ - приращение позиции s на "другой символ"
пробел - ничего не делает
Pointers - массив указателей на присваиваемые переменные

результат - количество действительно присвоенных переменных

Например, ...
Sscanf('Name. Bill   Time. 7:32.77   Age. 8',
'. %s . %d:%f . %d', [@Name, @hrs, @min, @age]);

возвратит ...
Name = Bill  hrs = 7  min = 32.77  age = 8 }

function Sscanf(const s: string; const fmt: string;

  const Pointers: array of Pointer): Integer;
var

  i, j, n, m: integer;
  s1: string;
  L: LongInt;
  X: Extended;

  function GetInt: Integer;
  begin
    s1 := '';
    while (s[n] = ' ') and (Length(s) > n) do
      inc(n);
    while (s[n] in ['0'..'9', '+', '-'])
      and (Length(s) >= n) do
    begin
      s1 := s1 + s[n];
      inc(n);
    end;
    Result := Length(s1);
  end;

  function GetFloat: Integer;
  begin
    s1 := '';
    while (s[n] = ' ') and (Length(s) > n) do
      inc(n);
    while (s[n] in ['0'..'9', '+', '-', '.', 'e', 'E'])
      and (Length(s) >= n) do
    begin
      s1 := s1 + s[n];
      inc(n);
    end;
    Result := Length(s1);
  end;

  function GetString: Integer;
  begin
    s1 := '';
    while (s[n] = ' ') and (Length(s) > n) do
      inc(n);
    while (s[n] <> ' ') and (Length(s) >= n) do
    begin
      s1 := s1 + s[n];
      inc(n);
    end;
    Result := Length(s1);
  end;

  function ScanStr(c: Char): Boolean;
  begin
    while (s[n] <> c) and (Length(s) > n) do
      inc(n);
    inc(n);

    if (n <= Length(s)) then
      Result := True
    else
      Result := False;
  end;

  function GetFmt: Integer;
  begin
    Result := -1;

    while (TRUE) do
    begin
      while (fmt[m] = ' ') and (Length(fmt) > m) do
        inc(m);
      if (m >= Length(fmt)) then
        break;

      if (fmt[m] = '%') then
      begin
        inc(m);
        case fmt[m] of
          'd': Result := vtInteger;
          'f': Result := vtExtended;
          's': Result := vtString;
        end;
        inc(m);
        break;
      end;

      if (ScanStr(fmt[m]) = False) then
        break;
      inc(m);
    end;
  end;

begin

  n := 1;
  m := 1;
  Result := 0;

  for i := 0 to High(Pointers) do
  begin
    j := GetFmt;

    case j of
      vtInteger:
        begin
          if GetInt > 0 then
          begin
            L := StrToInt(s1);
            Move(L, Pointers[i]^, SizeOf(LongInt));
            inc(Result);
          end
          else
            break;
        end;

      vtExtended:
        begin
          if GetFloat > 0 then
          begin
            X := StrToFloat(s1);
            Move(X, Pointers[i]^, SizeOf(Extended));
            inc(Result);
          end
          else
            break;
        end;

      vtString:
        begin
          if GetString > 0 then
          begin
            Move(s1, Pointers[i]^, Length(s1) + 1);
            inc(Result);
          end
          else
            break;
        end;

    else
      break;
    end;
  end;
end;

end.


Source: http://delphiworld.narod.ru/
ID: 00909



// Parse a string, for example: 
// How do I get the "B" from "A|B|C|D|E|F"? 

function Parse(Char, S: string; Count: Integer): string;
var
  I: Integer;
  T: string;
begin
  if S[Length(S)] <> Char then
    S := S + Char;
  for I := 1 to Count do
  begin
    T := Copy(S, 0, Pos(Char, S) - 1);
    S := Copy(S, Pos(Char, S) + 1, Length(S));
  end;
  Result := T;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(Parse('|', 'A|B|C|D|E|F', 2));
end;

{ 
  Parameters: 

  Parse([Character, for example "|"], [The string], 
  [The number, the "B" is the 2nd part of the string]); 

  This function is handy to use when sending data over the internet, 
  for example a chat program: Name|Text. Note: Be sure there's no "Char" in the string! 
  Use a unused character like "|" or "?". 
}


Source: Взято с сайта: http://www.swissdelphicenter.ch
ID: 00910