нечувствительный к регистру Pos

Я на самом деле все еще пытаюсь изобразить этот вопрос сам, но существует одна большая премия для MSBuild здесь: использование того же файла типа "build" для локальной непрерывной интеграции путем вызова msbuild.exe непосредственно, в то время как также способность использовать серверную сторону VSTS непрерывная интеграция с тем же файлом типа "build" (хотя наиболее вероятные различные свойства/настройки).

т.е. по сравнению с поддержкой TeamCity сценариев MSBuild, VSTS [только 110] поддержки сценарии MSBuild! Я бездельничал это в прошлом exec'ing NAnt из MSBuild; я видел, что другие рекомендуют эту практику, а также реверс, но это просто кажется kludgey мне, таким образом, я пытаюсь не сделать это, если я могу избежать его. Так, когда Вы используете "полный стек Microsoft" (VSTS и TFS), я предложил бы просто придерживаться сценариев MSBuild.

11
задан smartins 12 October 2009 в 06:47
поделиться

8 ответов

Эта версия моего предыдущего ответа работает как в D2007, так и в D2010.

  • В Delphi 2007 CharUpCaseTable составляет 256 байт
  • В Delphi 2010 это 128 КБ (65535 * 2).

Причина в размере Char . В более старой версии Delphi мой исходный код поддерживал только текущий набор символов локали при инициализации. Мой InsensPosEx примерно в 4 раза быстрее вашего кода. Конечно, можно пойти и быстрее, но мы потеряем простоту.

type
  TCharUpCaseTable = array [Char] of Char;

var
  CharUpCaseTable: TCharUpCaseTable;

procedure InitCharUpCaseTable(var Table: TCharUpCaseTable);
var
  n: cardinal;
begin
  for n := 0 to Length(Table) - 1 do
    Table[Char(n)] := Char(n);
  CharUpperBuff(@Table, Length(Table));
end;

function InsensPosEx(const SubStr, S: string; Offset: Integer = 1): Integer;
var
  n:            Integer;
  SubStrLength: Integer;
  SLength:      Integer;
label
  Fail;
begin
  Result := 0;
  if S = '' then Exit;
  if Offset <= 0 then Exit;

  SubStrLength := Length(SubStr);
  SLength := Length(s);

  if SubStrLength > SLength then Exit;

  Result := Offset;
  while SubStrLength <= (SLength-Result+1) do 
  begin
    for n := 1 to SubStrLength do
      if CharUpCaseTable[SubStr[n]] <> CharUpCaseTable[s[Result+n-1]] then
        goto Fail;
      Exit;
Fail:
    Inc(Result);
  end;
  Result := 0;
end;

//...

initialization
  InitCharUpCaseTable({var}CharUpCaseTable);
9
ответ дан 3 December 2019 в 01:13
поделиться

Для этого встроенная функция Delphi находится как в AnsiStrings.ContainsText для AnsiStrings, так и в StrUtils.ContainsText для строк Unicode.

] Однако в фоновом режиме они используют логику, очень похожую на вашу.

Независимо от того, в какой библиотеке, подобные функции всегда будут медленными: особенно, чтобы быть максимально совместимыми с Unicode, они должны иметь довольно много накладные расходы. А поскольку они находятся внутри цикла, это стоит больших денег.

Единственный способ обойти эти накладные расходы - это как можно больше выполнять эти преобразования вне цикла.

Итак: следуйте своему собственному предложению, и у вас есть действительно хорошее решение.

- jeroen

24
ответ дан 3 December 2019 в 01:13
поделиться

Я также столкнулся с проблемой преобразования FastStrings, который использовал поиск Бойера-Мура (BM) для увеличения скорости для D2009 и D2010. Поскольку многие из моих поисков ищут только один символ, а большинство из них ищут неалфавитные символы, моя версия SmartPos D2010 имеет версию с перегрузкой с широким символом в качестве первого аргумента и выполняет простой цикл по строке найти их. Я использую верхний регистр обоих аргументов, чтобы обрабатывать несколько регистров без учета регистра. Я считаю, что для моих приложений скорость этого решения сравнима с FastStrings.

В случае «поиска строки» моим первым шагом было использование SearchBuf, использование верхнего регистра и принятие штрафа, но недавно я изучал возможность использования реализации Unicode BM. Как вы можете быть в курсе, BM плохо или легко масштабируется до кодировок пропорций Unicode, но есть реализация Unicode BM в Soft Gems . Это предшествует D2009 и D2010, но похоже, что преобразовать его будет довольно легко. Автор, Майк Лишке, решает проблему с верхним регистром, включив в него таблицу верхнего регистра Unicode размером 67 КБ, и это может оказаться слишком большим шагом для моих скромных требований. Так как мои поисковые строки обычно короткие (хотя и не такие короткие, как ваш пример из трех символов), накладные расходы на Unicode BM также могут быть платой, которую не стоит платить: преимущество BM увеличивается с увеличением длины искомой строки.

Это определенно ситуация, когда потребуется тестирование производительности с некоторыми примерами из реальных приложений, прежде чем включать этот Unicode BM в мои собственные приложения.

Изменить: некоторые базовые тесты показывают, что я был прав, опасаясь решения "Unicode Tuned Boyer-Moore". В моей среде UTBM приводит к большему размеру кода и большему времени. Я мог бы рассмотреть возможность его использования, если бы мне потребовались некоторые из дополнительных возможностей, которые предоставляет эта реализация (обработка суррогатов и поиск только целых слов).

5
ответ дан 3 December 2019 в 01:13
поделиться

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

function XPos( const cSubStr, cString :string ) :integer;
var
  nLen0, nLen1, nCnt, nCnt2 :integer;
  cFirst :Char;
begin
  nLen0 := Length(cSubStr);
  nLen1 := Length(cString);

  if nLen0 > nLen1 then
    begin
      // the substr is longer than the cString
      result := 0;
    end

  else if nLen0 = 0 then
    begin
      // null substr not allowed
      result := 0;
    end

  else

    begin

      // the outer loop finds the first matching character....
      cFirst := UpCase( cSubStr[1] );
      result := 0;

      for nCnt := 1 to nLen1 - nLen0 + 1 do
        begin

          if UpCase( cString[nCnt] ) = cFirst then
            begin
              // this might be the start of the substring...at least the first
              // character matches....
              result := nCnt;

              for nCnt2 := 2 to nLen0 do
                begin

                  if UpCase( cString[nCnt + nCnt2 - 1] ) <> UpCase( cSubStr[nCnt2] ) then
                    begin
                      // failed
                      result := 0;
                      break;
                    end;

                end;

            end;


          if result > 0 then
            break;
        end;


    end;
end;

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

Библиотека кодов джедаев содержит StrIPos и ​​тысячи других полезных функций, дополняющих RTL Delphi. Когда я еще много работал в Delphi, JCL и его визуальный брат JVCL были одними из первых вещей, которые я добавил в только что установленный Delphi.

1
ответ дан 3 December 2019 в 01:13
поделиться

Я думаю, что преобразование в верхний или нижний регистр перед Pos - лучший способ, но вам следует попытаться вызывать функции AnsiUpperCase / AnsiLowerCase как можно реже.

0
ответ дан 3 December 2019 в 01:13
поделиться

В этом случае я не смог найти подход, который был бы даже лучше, чем Pos () +, не говоря уже о лучшем, чем Pos () + некоторая форма нормализации строк (преобразование верхнего / нижнего регистра).

Это не совсем удивительно, поскольку при тестировании обработки строк Unicode в Delphi 2009 я обнаружил, что процедура Pos () RTL значительно улучшилась по сравнению с Delphi 7, что частично объясняется тем, что аспекты библиотек FastCode были включены в RTL для Некоторое время назад.

С другой стороны, библиотека FastStrings - iirc - уже давно не обновлялась существенно. В ходе тестов я обнаружил, что многие подпрограммы FastStrings фактически заменены эквивалентными функциями RTL (за некоторыми исключениями, которые объясняются неизбежными накладными расходами, вызванными дополнительными сложностями Unicode).

0
ответ дан 3 December 2019 в 01:13
поделиться

Вместо AnsiUpperCase вы можете использовать Table, это намного быстрее. Я изменил свой старый код. Это очень просто и очень быстро. Проверьте это:

type
  TAnsiUpCaseTable = array [AnsiChar] of AnsiChar;

var
  AnsiTable: TAnsiUpCaseTable;

procedure InitAnsiUpCaseTable(var Table: TAnsiUpCaseTable);
var
  n: cardinal;
begin
  for n := 0 to SizeOf(TAnsiUpCaseTable) -1 do
  begin
    AnsiTable[AnsiChar(n)] := AnsiChar(n);
    CharUpperBuff(@AnsiTable[AnsiChar(n)], 1);
  end;
end;

function UpCasePosEx(const SubStr, S: string; Offset: Integer = 1): Integer;
var
  n              :integer;
  SubStrLength   :integer;
  SLength        :integer;
label
  Fail;
begin
  SLength := length(s);
  if (SLength > 0) and (Offset > 0) then begin
    SubStrLength := length(SubStr);
    result := Offset;
    while SubStrLength <= SLength - result + 1 do begin
      for n := 1 to SubStrLength do
        if AnsiTable[SubStr[n]] <> AnsiTable[s[result + n -1]] then
          goto Fail;
      exit;
Fail:
      inc(result);
    end;
  end;
  result := 0;
end;

initialization
  InitAnsiUpCaseTable(AnsiTable);
end.
0
ответ дан 3 December 2019 в 01:13
поделиться
Другие вопросы по тегам:

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