Что самый быстрый путь состоит в том, чтобы Проанализировать строку в Delphi?

Метод main () требуется в публичном классе.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        public static int sum(int num1, int num2, int num3)
        {
            int total;
            total = num1 + num2 + num3;
            return total;
        }
        public static void Main(string[] args)
        {
            Console.Write("\n\nFunction to calculate the sum of two numbers :\n");
            Console.Write("--------------------------------------------------\n");
            Console.Write("Enter a number1: ");
            int n1 = Convert.ToInt32(Console.ReadLine());
            Console.Write("Enter a number2: ");
            int n2 = Convert.ToInt32(Console.ReadLine());
            Console.Write("Enter a number3: ");
            int n3 = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("\nThe sum of three numbers is : {0} \n", sum(n1, n2, n3));
        }
    }
}

Проверьте здесь: https://dotnetfiddle.net/p9E9Rw

9
задан 7 revs 16 November 2008 в 18:05
поделиться

9 ответов

  • Используйте PChar, увеличивающий для скорости обработки
  • Если некоторые маркеры не нужны, только копируют маркерные данные по требованию
  • Скопируйте PChar в локальную переменную при фактическом сканировании через символы
  • Сохраните исходные данные в единственном буфере, если Вы не должны обрабатывать линию за линией, и даже затем, рассмотрите строку обработки, обрабатывающую как отдельный маркер в устройстве распознавания лексического анализатора
  • Рассмотрите обработку буфера массива байтов, который прибыл прямо из файла, если Вы определенно знаете кодирование; при использовании Delphi 2009 используйте PAnsiChar вместо PChar, если, конечно, Вы не знаете, что кодирование является UTF16-LE.
  • Если Вы знаете, что единственный пробел будет № 32 (пространство ASCII), или столь же ограниченный набор символов, могут быть некоторые умные взломы побитовой обработки, которые могут позволить Вам обработать 4 байта во время с помощью Целочисленного сканирования. Я не ожидал бы большие победы здесь, хотя, и код будет совершенно непонятно.

Вот демонстрационный лексический анализатор, который должен быть довольно эффективным, но он предполагает, что все исходные данные находятся в единственной строке. Переделка его для обработки буферов умеренно хитра из-за очень длинных маркеров.

type
  TLexer = class
  private
    FData: string;
    FTokenStart: PChar;
    FCurrPos: PChar;
    function GetCurrentToken: string;
  public
    constructor Create(const AData: string);
    function GetNextToken: Boolean;
    property CurrentToken: string read GetCurrentToken;
  end;

{ TLexer }

constructor TLexer.Create(const AData: string);
begin
  FData := AData;
  FCurrPos := PChar(FData);
end;

function TLexer.GetCurrentToken: string;
begin
  SetString(Result, FTokenStart, FCurrPos - FTokenStart);
end;

function TLexer.GetNextToken: Boolean;
var
  cp: PChar;
begin
  cp := FCurrPos; // copy to local to permit register allocation

  // skip whitespace; this test could be converted to an unsigned int
  // subtraction and compare for only a single branch
  while (cp^ > #0) and (cp^ <= #32) do
    Inc(cp);

  // using null terminater for end of file
  Result := cp^ <> #0;

  if Result then
  begin
    FTokenStart := cp;
    Inc(cp);
    while cp^ > #32 do
      Inc(cp);
  end;

  FCurrPos := cp;
end;
33
ответ дан 4 December 2019 в 06:08
поделиться

Вот хромая реализация задницы очень простого лексического анализатора. Это могло бы дать Вам общее представление.

Отметьте ограничения этого примера - никакая включенная буферизация, никакой Unicode (это - выборка из проекта Delphi 7). Вам, вероятно, были бы нужны те, которые в серьезной реализации.

{ Implements a simpe lexer class. } 
unit Simplelexer;

interface

uses Classes, Sysutils, Types, dialogs;

type

  ESimpleLexerFinished = class(Exception) end;

  TProcTableProc = procedure of object;

  // A very simple lexer that can handle numbers, words, symbols - no comment handling  
  TSimpleLexer = class(TObject)
  private
    FLineNo: Integer;
    Run: Integer;
    fOffset: Integer;
    fRunOffset: Integer; // helper for fOffset
    fTokenPos: Integer;
    pSource: PChar;
    fProcTable: array[#0..#255] of TProcTableProc;
    fUseSimpleStrings: Boolean;
    fIgnoreSpaces: Boolean;
    procedure MakeMethodTables;
    procedure IdentProc;
    procedure NewLineProc;
    procedure NullProc;
    procedure NumberProc;
    procedure SpaceProc;
    procedure SymbolProc;
    procedure UnknownProc;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Feed(const S: string);
    procedure Next;
    function GetToken: string;
    function GetLineNo: Integer;
    function GetOffset: Integer;

    property IgnoreSpaces: boolean read fIgnoreSpaces write fIgnoreSpaces;
    property UseSimpleStrings: boolean read fUseSimpleStrings write fUseSimpleStrings;
  end;

implementation

{ TSimpleLexer }

constructor TSimpleLexer.Create;
begin
  makeMethodTables;
  fUseSimpleStrings := false;
  fIgnoreSpaces := false;
end;

destructor TSimpleLexer.Destroy;
begin
  inherited;
end;

procedure TSimpleLexer.Feed(const S: string);
begin
  Run := 0;
  FLineNo := 1;
  FOffset := 1;
  pSource := PChar(S);
end;

procedure TSimpleLexer.Next;
begin
  fTokenPos := Run;
  foffset := Run - frunOffset + 1;
  fProcTable[pSource[Run]];
end;

function TSimpleLexer.GetToken: string;
begin
  SetString(Result, (pSource + fTokenPos), Run - fTokenPos);
end;

function TSimpleLexer.GetLineNo: Integer;
begin
  Result := FLineNo;
end;

function TSimpleLexer.GetOffset: Integer;
begin
  Result := foffset;
end;

procedure TSimpleLexer.MakeMethodTables;
var
  I: Char;
begin
  for I := #0 to #255 do
    case I of
      '@', '&', '}', '{', ':', ',', ']', '[', '*',
        '^', ')', '(', ';', '/', '=', '-', '+', '#', '>', '<', '$',
        '.', '"', #39:
        fProcTable[I] := SymbolProc;
      #13, #10: fProcTable[I] := NewLineProc;
      'A'..'Z', 'a'..'z', '_': fProcTable[I] := IdentProc;
      #0: fProcTable[I] := NullProc;
      '0'..'9': fProcTable[I] := NumberProc;
      #1..#9, #11, #12, #14..#32: fProcTable[I] := SpaceProc;
    else
      fProcTable[I] := UnknownProc;
    end;
end;

procedure TSimpleLexer.UnknownProc;
begin
  inc(run);
end;

procedure TSimpleLexer.SymbolProc;
begin
  if fUseSimpleStrings then
  begin
    if pSource[run] = '"' then
    begin
      Inc(run);
      while pSource[run] <> '"' do
      begin
        Inc(run);
        if pSource[run] = #0 then
        begin
          NullProc;
        end;
      end;
    end;
    Inc(run);
  end
  else
    inc(run);
end;

procedure TSimpleLexer.IdentProc;
begin
  while pSource[Run] in ['_', 'A'..'Z', 'a'..'z', '0'..'9'] do
    Inc(run);
end;

procedure TSimpleLexer.NumberProc;
begin
  while pSource[run] in ['0'..'9'] do
    inc(run);
end;

procedure TSimpleLexer.SpaceProc;
begin
  while pSource[run] in [#1..#9, #11, #12, #14..#32] do
    inc(run);
  if fIgnoreSpaces then Next;
end;

procedure TSimpleLexer.NewLineProc;
begin
  inc(FLineNo);
  inc(run);
  case pSource[run - 1] of
    #13:
      if pSource[run] = #10 then inc(run);
  end;
  foffset := 1;
  fRunOffset := run;
end;

procedure TSimpleLexer.NullProc;
begin
  raise ESimpleLexerFinished.Create('');
end;

end.
4
ответ дан 4 December 2019 в 06:08
поделиться

Я сделал лексический анализатор на основе механизма состояния (DFA). Это работает с таблицей и довольно быстро. Но существуют возможные более быстрые опции.

Это также зависит от языка. Простой язык может возможно иметь умный алгоритм.

Таблица является массивом записей каждый содержащий 2 символа и 1 целое число. Для каждого маркера лексический анализатор идет через таблицу, запускающуюся в положении 0:

state := 0;
result := tkNoToken;
while (result = tkNoToken) do begin
  if table[state].c1 > table[state].c2 then
    result := table[state].value
  else if (table[state].c1 <= c) and (c <= table[state].c2) then begin
    c := GetNextChar();
    state := table[state].value;
  end else
    Inc(state);
end;

Это просто и работает как очарование.

3
ответ дан 4 December 2019 в 06:08
поделиться

Если скорость является существенной, пользовательский код является ответом. Проверьте Windows API, который отобразит Ваш файл в память. Можно затем просто использовать указатель на следующий символ, чтобы сделать маркеры, идущие через как требуется.

Это - мой код для того, чтобы сделать отображение:

procedure TMyReader.InitialiseMapping(szFilename : string);
var
//  nError : DWORD;
    bGood : boolean;
begin
    bGood := False;
    m_hFile := CreateFile(PChar(szFilename), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);
    if m_hFile <> INVALID_HANDLE_VALUE then
    begin
        m_hMap := CreateFileMapping(m_hFile, nil, PAGE_READONLY, 0, 0, nil);
        if m_hMap <> 0 then
        begin
            m_pMemory := MapViewOfFile(m_hMap, FILE_MAP_READ, 0, 0, 0);
            if m_pMemory <> nil then
            begin
                htlArray := Pointer(Integer(m_pMemory) + m_dwDataPosition);
                bGood := True;
            end
            else
            begin
//              nError := GetLastError;
            end;
        end;
    end;
    if not bGood then
        raise Exception.Create('Unable to map token file into memory');
end;
2
ответ дан 4 December 2019 в 06:08
поделиться

Я думаю, что самое большое узкое место всегда будет получением файла в память. После того как у Вас есть он в памяти (очевидно, не все это сразу, но я работал бы с буферами на вашем месте), фактический парсинг должен быть незначительным.

1
ответ дан 4 December 2019 в 06:08
поделиться

Скорость всегда будет относительно того, что Вы делаете, после того как она анализируется. Лексический синтаксический анализатор безусловно является самым быстрым методом преобразования в маркеры от текстового потока независимо от размера. TParser в единице классов является великолепным местом для запуска.

Лично ее некоторое время, так как я должен был записать синтаксический анализатор, но другой более датированный все же испытанный и истинный метод должен будет использовать LEX/YACC для создания грамматики затем, имеют его, преобразовывают грамматику в код, который можно использовать для выполнения обработки. DYacc является версией Delphi... не уверенной, если он все еще компилирует или нет, но стоящий взгляда, если Вы хотите сделать вещи старая школа. Книга дракона здесь имела бы большую справку, если можно найти копию.

1
ответ дан 4 December 2019 в 06:08
поделиться

Это вызывает другой вопрос - Как большой? Дайте нам ключ к разгадке как # строк или # или Мбит (Гбит)? Затем мы будем знать, умещается ли это в памяти, должно быть находящимся на диске и т.д.

При первичной обработке я использовал бы свой WordList (S: Строка; AList: TStringlist);

затем можно получить доступ к каждому маркеру как к Alist[n]... или отсортировать их или что бы то ни было.

1
ответ дан 4 December 2019 в 06:08
поделиться

Самый быстрый способ написать код состоял бы в том, чтобы, вероятно, создать TStringList и присвоить каждую строку в Вашем текстовом файле к свойству CommaText. По умолчанию пробел является разделителем, таким образом, Вы получите один объект StringList на маркер.

MyStringList.CommaText := s;
for i := 0 to MyStringList.Count - 1 do
begin
  // process each token here
end;

Вы, вероятно, получите лучшую производительность путем парсинга каждой строки сами, все же.

0
ответ дан 4 December 2019 в 06:08
поделиться

Прокрутка Ваше собственное является самым быстрым путем наверняка. Для больше по этой теме, Вы видели исходный код Synedit, который содержит лексические анализаторы (названный маркерами в контексте проекта) приблизительно для любого языка на рынке. Я предлагаю, чтобы Вы взяли один из тех лексических анализаторов как основа и изменили для Вашего собственного использования.

0
ответ дан 4 December 2019 в 06:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: