Я на самом деле все еще пытаюсь изобразить этот вопрос сам, но существует одна большая премия для MSBuild здесь: использование того же файла типа "build" для локальной непрерывной интеграции путем вызова msbuild.exe непосредственно, в то время как также способность использовать серверную сторону VSTS непрерывная интеграция с тем же файлом типа "build" (хотя наиболее вероятные различные свойства/настройки).
т.е. по сравнению с поддержкой TeamCity сценариев MSBuild, VSTS [только 110] поддержки сценарии MSBuild! Я бездельничал это в прошлом exec'ing NAnt из MSBuild; я видел, что другие рекомендуют эту практику, а также реверс, но это просто кажется kludgey мне, таким образом, я пытаюсь не сделать это, если я могу избежать его. Так, когда Вы используете "полный стек Microsoft" (VSTS и TFS), я предложил бы просто придерживаться сценариев MSBuild.
Эта версия моего предыдущего ответа работает как в D2007, так и в D2010.
CharUpCaseTable
составляет 256 байт Причина в размере 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);
Для этого встроенная функция Delphi находится как в AnsiStrings.ContainsText для AnsiStrings, так и в StrUtils.ContainsText для строк Unicode.
] Однако в фоновом режиме они используют логику, очень похожую на вашу.
Независимо от того, в какой библиотеке, подобные функции всегда будут медленными: особенно, чтобы быть максимально совместимыми с Unicode, они должны иметь довольно много накладные расходы. А поскольку они находятся внутри цикла, это стоит больших денег.
Единственный способ обойти эти накладные расходы - это как можно больше выполнять эти преобразования вне цикла.
Итак: следуйте своему собственному предложению, и у вас есть действительно хорошее решение.
- jeroen
Я также столкнулся с проблемой преобразования 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 приводит к большему размеру кода и большему времени. Я мог бы рассмотреть возможность его использования, если бы мне потребовались некоторые из дополнительных возможностей, которые предоставляет эта реализация (обработка суррогатов и поиск только целых слов).
Вот один, который я написал и использую в течение многих лет:
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;
Библиотека кодов джедаев содержит StrIPos и тысячи других полезных функций, дополняющих RTL Delphi. Когда я еще много работал в Delphi, JCL и его визуальный брат JVCL были одними из первых вещей, которые я добавил в только что установленный Delphi.
Я думаю, что преобразование в верхний или нижний регистр перед Pos - лучший способ, но вам следует попытаться вызывать функции AnsiUpperCase / AnsiLowerCase как можно реже.
В этом случае я не смог найти подход, который был бы даже лучше, чем Pos () +, не говоря уже о лучшем, чем Pos () + некоторая форма нормализации строк (преобразование верхнего / нижнего регистра).
Это не совсем удивительно, поскольку при тестировании обработки строк Unicode в Delphi 2009 я обнаружил, что процедура Pos () RTL значительно улучшилась по сравнению с Delphi 7, что частично объясняется тем, что аспекты библиотек FastCode были включены в RTL для Некоторое время назад.
С другой стороны, библиотека FastStrings - iirc - уже давно не обновлялась существенно. В ходе тестов я обнаружил, что многие подпрограммы FastStrings фактически заменены эквивалентными функциями RTL (за некоторыми исключениями, которые объясняются неизбежными накладными расходами, вызванными дополнительными сложностями Unicode).
Вместо 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.