Ключевые слова в Delphi

Зарезервированные слова Delphi

var A, B : Integer; begin A:=3; B:=4; A:=A*A+B*B; end;

if (условие) then (действие) else (альтернатива) ;

Слова if (если), then (тогда), else (иначе) — зарезервированные. Действие и else альтернатива — это любые операторы Delphi, или несколько операторов, заключённых в логические скобки begin/end, или вызов подпрограммы. Если условие истинно, то выполняется действие, если ложно, то выполняется альтернатива.

(применяется, когда известно количество повторений цикла)

for счётчик := выражение-1 to выражение-2 do действие ;

Возможна работа оператора цикла, при котором переменная-счётчик будет не увеличиваться, а уменьшаться. В этом случае ключевое слово to заменяется на downto:

for счётчик := выражение-1 downto выражение-2 do действие ;

Цикл с предусловием (применяется, когда неизвестно количество повторений цикла)

while условие do тело цикла ;

Этот цикл будет выполняться до тех пор, пока истинно условие (логическое выражение, возвращающее значение типа Boolean). При этом если это выражение сразу равно false, тело цикла не будет выполнено ни разу. Нужно очень внимательно следить за написанием условия и контролем завершения цикла, так как в результате ошибки цикл while будет повторяться бесконечное количество раз, что приведёт к «зацикливанию» и «зависанию» программы.

Цикл с постусловием

(применяется, когда неизвестно количество повторений цикла)

repeat тело цикла until условие ;

Повторения сначала выполняет тело цикла, а затем уже проверяет выполнение условия: Таким образом, этот вариант цикла гарантирует, что тело цикла будет выполнен по крайней мере один раз. И будет выполняться до тех пор, пока условие не станет истинным (т.е. true). Стоит отметить, что это единственный оператор Delphi, в котором тело цикла не требуется заключать в логические скобки begin/end. Начало и конец тела цикла определяются по ключевым словам repeat и until.

Позволяет изменить последовательность выполнения программы. В качестве метки может использоваться любой допустимый идентификатор или число в диапазоне от 0 до 9999. Метку предварительно необходимо объявить в разделе описания переменных, но с помощью не ключевого слова var, а ключевого слова label:

Что такое ключевое слово inline в delphi

12 [2009-07-22 15:24:00]

может кто-нибудь сказать, что такое использование встроенного ключевого слова в delphi

5 ответов

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

Это оптимизация для (очень) малых функций, где накладные расходы на вызов будут значительными. Вы найдете много примеров, например, для windows.pas

Что на самом деле происходит, зависит от сложности функции, открытого/закрытого доступа и версии Delphi.

Он сообщает компилятору генерировать код для встроенного; рутина на том месте, где она называется, вместо того, чтобы прыгать к рутине и обратно.

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

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

11 MarkF [2009-07-22 15:39:00]

Другие ответили, что делает inline, но я просто хотел указать, что есть опция Compiler для установки встроенного, выключенного или автоматического. Ознакомьтесь с «Процедурами и функциями вызова» в документах D2009 для очень хорошего объяснения механики встроенного. Здесь ссылка на онлайн-документы:

1 Cruachan [2009-07-22 15:40:00]

Он заимствован из C в том смысле, что он сообщает компилятору, что это короткая подпрограмма, которая часто вызывается, и рекомендует компилятору рассматривать эту функцию как макрос и интегрирует код функции непосредственно в программу в указанной точке, а не используйте вызов функции.

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

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

0 Alex [2015-05-10 16:17:00]

Нажмите Ctrl + Alt + C (полное окно отладки CPU) во время отладки в Delphi, прежде чем вызывать свою встроенную функцию. И вы увидите, что встроенные функции запускаются без «вызова» и wo перехода на другой адрес. Это функция оптимизации.

Каков самый быстрый способ проверить ключевое слово в списке ключевых слов в Delphi?

У меня есть небольшой список ключевых слов. То, что я действительно хотел бы сделать, сродни:

К сожалению, оператор CASE не может использоваться так же, как для строк.

Я мог бы использовать прямую IF, если ELSE IF сконструировать, например:

но я слышал, что это относительно неэффективно.

Вместо этого я сделал следующее:

Это, конечно, не лучший стиль программирования, но он отлично подходит для меня и до сих пор не менял.

Итак, каков наилучший способ переписать это в Delphi, чтобы он был простым, понятным, но и быстрым?

(Для справки, я использую Delphi 2009 с строками Unicode.)

Тоби рекомендовал, чтобы я просто использовал конструкцию If Then Else. Оглядываясь на мои примеры, в которых используется оператор CASE, я вижу, как это жизнеспособный ответ. К сожалению, мое включение CASE непреднамеренно скрыло мой реальный вопрос.

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

Так что действительно хочу знать, есть ли что-то лучше:

Эквивалент If Then Else не выглядит лучше в этом случае:

В комментарии Барри к вопросу Корнеля он упоминает TDictionary Generic. Я еще не нашел новых коллекций Generic, и, похоже, я должен вникать в них. Мой вопрос здесь будет заключаться в том, построены ли они для эффективности и как бы использовать TDictionary для сравнения в взглядах и в скорости для двух вышеперечисленных строк?

В более позднем профилировании я обнаружил, что конкатенация строк как в: (» + MyKeyword + ») ОЧЕНЬ дорогая по времени, и ее следует избегать, когда это возможно. Практически любое другое решение лучше, чем делать это.

В основном я использую функцию IndexText из StrUtils для этой цели. Он похож на ваш подход pos, но возвращаемое значение не зависит от индивидуальной длины строк. В качестве трюка он также нечувствителен к регистру (используйте IndexStr, если вы этого не хотите).

Комментарий к этим функциям фактически упоминает конструкцию случая:

В общем, не используйте строки как «ключи», используйте перечисления — они безопаснее, и вы получаете большую часть увеличения скорости.

К сожалению, Delphi (насколько мне известно) не имеет стандартной реализации хэш-таблицы, которая будет проста в использовании, однако вы всегда можете сворачивать свои собственные.

BTW, code for SEX звучит гораздо веселее, чем «код для пива»: P

Вы можете использовать таблицу const (которая должна быть отсортирована по альфа) и быстрая двоичная сортировка. Он очень эффективен и не требует никакого хеширования.

И вот несколько примеров ключевых слов:

И он очень прост в использовании:

Вы можете легко изменить функцию IsKeyWord(), чтобы вернуть индекс маркера, если вам это нужно.

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

можно заменить на

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

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

является лучшим решением. Ваше собственное решение очень неэлегантное, и для минимального повышения эффективности его не стоит. Конструкция if then else идеально подходит для того, что вы хотите.

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

Один из них — использовать хэш-карту строки, которая похожа на список, индексированный по строкам. Значения в списке будут указателями процедур для кода, который вы хотите выполнить для каждой строки. Все процедуры должны иметь одинаковые точные параметры — и вам придется писать карту хэша самостоятельно или найти тот, который вы можете использовать, например. в JVCL.

Два, и это что-то странное, я пробовал один раз: если и только если строки вашего идентификатора соответствуют 4 символам (как и во всех ваших примерах), и они являются строками ansi (не строки Unicode), вы можете отобразить строки непосредственно к целым числам. 32-разрядное целое эквивалентно по размеру 4-байтовой строке, поэтому вы можете сделать:

Любой строковый идентификатор, длина которого меньше 4 символов, должна быть заполнена пробелами, а строки чувствительны к регистру ( «chil» и «CHIL» дают разные значения). Чтобы использовать это с аргументом case, вам придется предварительно скопировать значения, которые могут быть или не подходят для вашей цели:

И, наконец, вы можете иметь оператор case:

Это код «особого ухода» и может иметь значение только в том случае, если у вас есть сотни или более строк вашего идентификатора — это действительно не должно быть сделано вообще. Конечно, это легко сломать. Я согласен, что утверждения этого случая более быстрые, чем бесконечные шествия блоков. else.

отказ от ответственности: ответ основан на обновленном описании проблемы, т.е. просто проверяет соответствие строки или нет.

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

  • Сколько ключевых слов мы говорим? (какой порядок величины)
  • установлен ли набор ключевых слов?
  • Много ли повторений во входном наборе? (то есть повторяются одни и те же ключевые слова X)
  • Каков ожидаемый коэффициент хита/промаха? Ожидаете ли вы совпадения с одним ключевым словом для каждых тысяч входных слов, или вы ожидаете, что почти каждое слово будет найдено?
  • для небольшого количества ключевых слов (скажем, около 20, в зависимости от реализации), накладные расходы хеширования станут важными.
  • Если вы получите, можете получить идеальную схему хэширования (см. здесь для примера на C), вы можете избавиться от любой цепочки или аналогичную схему, сбрасывая некоторые важные циклы. И снова это потребует, чтобы как ваши ключевые слова, так и набор ввода были известны спереди, что маловероятно.
  • Если в ключевых словах (и большой коллекции хеш файлов) есть много повторений, может помочь небольшой локальный кеш последних X слов.
  • если вы ожидаете много вопиющих промахов (или ваш хеш-алгоритм очень неэффективен; P), trie может быть более эффективным, чем хеш-таблица.
Илон Маск рекомендует:  Загрузка нескольких файлов

Большинство из них немного экстремальны для обычных задач настройки производительности. Я бы, вероятно, предварительно профилировал стандартные «хешированные» реализации (delphi generics, jcl и т.д.), Чтобы увидеть, какой из них лучше всего подходит для вашей задачи.

Какой самый быстрый способ проверить ключевое слово в списке ключевых слов в Delphi?

У меня есть небольшой список ключевых слов. То, что я действительно хотел бы сделать, сродни:

К сожалению, оператор CASE нельзя использовать таким образом для строк.

Я мог бы использовать прямую конструкцию IF THEN ELSE IF, например:

но я слышал это относительно неэффективно.

Вместо этого я делал следующее:

Это, конечно, не лучший стиль программирования, но он прекрасно работает для меня, и до сих пор ничего не изменилось.

Итак, как лучше всего переписать это в Delphi, чтобы оно было простым, понятным, но и быстрым?

(Для справки, я использую Delphi 2009 со строками Unicode.)

Тоби рекомендовал мне просто использовать конструкцию If Then Else. Оглядываясь назад на мои примеры, в которых использовался оператор CASE, я вижу, насколько это приемлемый ответ. К сожалению, мое включение в CASE непреднамеренно скрыло мой настоящий вопрос.

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

Так что на самом деле я хочу знать, есть ли что-нибудь лучше, чем:

Эквивалент If Then Else не выглядит лучше в этом случае:

В комментарии Барри к вопросу Корнеля он упоминает об универсальном TDictionary. Я еще не изучал новые коллекции Generic, и, похоже, я должен в них углубиться. Мой вопрос здесь будет заключаться в том, построены ли они для эффективности, и как бы использование TDictionary сравнивалось по внешнему виду и по скорости с двумя вышеупомянутыми строками?

В последующем профилировании я обнаружил, что объединение строк, как в: (» + MyKeyword + »), ОЧЕНЬ дорого по времени и его следует по возможности избегать. Почти любое другое решение лучше, чем делать это.

8 ответов

В основном я использую функцию IndexText из StrUtils для этой цели. Это похоже на ваш подход pos, но возвращаемое значение не зависит от индивидуальной длины строк. Как трюк, он также нечувствителен к регистру (используйте IndexStr, если вы этого не хотите).

Комментарий к этим функциям фактически упоминает конструкцию case:

В общем, не используйте строки в качестве «ключей», используйте перечисления — они безопаснее, и вы значительно увеличите скорость.

К сожалению, в Delphi (насколько я знаю) нет стандартной реализации хеш-таблиц, которую было бы легко использовать, однако вы всегда можете свернуть свою собственную.

Кстати, code for SEX звучит гораздо веселее, чем «будет код для пива»: P

Вы можете использовать таблицу const (которая должна быть отсортирована по альфа) и быструю двоичную сортировку. Это очень эффективно и не требует хеширования.

Вот функция для использования:

А вот несколько примеров ключевых слов:

И это очень легко использовать:

Вы можете легко изменить функцию IsKeyWord (), чтобы она возвращала индекс токена, если вам это нужно.

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

может быть заменено

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

Взяв это на максимум, вы могли бы реализовать конечный автомат, который использует PChar для вычисления следующего состояния, которое будет переходить к else случаю, как только будет найден первый несовпадающий символ. Это будет быстрее, чем любое решение с использованием хэшей.

безусловно лучшее решение. Ваше собственное решение очень не элегантно и для незначительного повышения эффективности оно того не стоит. Конструкция if then else идеально подходит для того, что вы хотите.

Для самого чистого кода лучше использовать case с перечислениями или if..else со строками, как предлагали другие. Однако есть несколько решений в глуши, если вы действительно хотите пойти туда.

Одним из них является использование строки хеш-карты, которая похожа на список, «проиндексированный» строками. Значения в списке будут указателями на код, который вы хотите выполнить для каждой строки. Все процедуры должны иметь одинаковые точные параметры — и вам придется написать хеш-карту самостоятельно или найти такую, которую можно использовать, например, в JVCL.

Два, и это что-то странное, что я однажды попробовал: если и только если ваши строки идентификаторов помещаются в 4 символа (как во всех ваших примерах), и они являются строками ANSI (не Unicode), вы можете отобразить строки в целые числа непосредственно. 32-разрядное целое число эквивалентно по размеру 4-байтовой строке, поэтому вы можете сделать:

Любой строковый идентификатор, который короче 4 символов, должен быть дополнен пробелами, а строки чувствительны к регистру (chil и CHIL дают разные значения). Чтобы использовать это с оператором case, вам нужно предварительно вычислить значения, которые могут подходить или не подходить для вашей цели:

И, наконец, вы можете получить свое заявление по делу

Это код «особой заботы», и он может иметь значение только в том случае, если у вас есть сотни или более строк идентификаторов — на самом деле это вообще не нужно делать :) Это, конечно, легко сломать. Я согласен, хотя, что утверждения case более аккуратны, чем бесконечные процессии . else . блоков.

Отказ от ответственности: ответ основан на обновленной постановке задачи, т.е. просто проверяет, соответствует строка или нет.

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

  • Сколько ключевых слов мы говорим? (какой порядок величины)
  • фиксированный набор ключевых слов?
  • много ли повторений во входном наборе? (то есть одни и те же ключевые слова X часто повторяются)
  • каково ожидаемое соотношение попаданий / промахов? Ожидаете ли вы совпадение с одним ключевым словом для каждой тысячи входных слов или почти каждое слово будет найдено?
  • для небольшого количества ключевых слов (скажем, около 20, в зависимости от реализации) издержки хэширования станут важными.
  • Если вы можете получить идеальную схему хеширования (см. Пример на C), вы можете избавиться от любой цепочки или аналогичной схемы, сбрасывая некоторые важные циклы. Опять же, это потребовало бы, чтобы ваши ключевые слова и набор входных данных были известны заранее, что маловероятно.
  • если в ключевых словах много повторений (и большая коллекция хешей для сравнения), небольшой локальный кеш последних X слов может помочь.
  • если вы ожидаете много явных промахов (или ваш алгоритм хэширования очень неэффективен; P) три может быть более эффективным, чем хеш-таблица.

Большинство из них немного экстремальны для общих задач настройки производительности. Вероятно, я бы сначала профилировал стандартные реализации «хэшированного набора» (delphi generics, jcl и т. Д.), Чтобы увидеть, какая из них лучше всего работает в вашем наборе задач.

Вы также можете переключиться на более объектно-ориентированный подход и получить что-то вроде

и фабрика создаст команды для вас

Код вызова будет выглядеть так просто, как:

Таким образом, вы локализовали и инкапсулировали все строки ключевых слов в простой фабричный класс, что делает последующие изменения в языке ввода очень простыми. Использование этого подхода на основе команд имеет и другие преимущества, такие как простота расширения.

Я знаю, что это может быть истолковано как не ответ на ваш вопрос, потому что дело не в том, как быстро вы сможете это сделать. Но это еще один подход, о котором стоит подумать.

что такое использование встроенного ключевого слова в delphi

Кто-нибудь может сказать, как использовать встроенное ключевое слово в delphi

5 ответов

Это подсказка компилятору, что функция /процедура должна быть (если возможно) встроенной, то есть при вызове она должна быть расширена как макрос, а не вызываться.

Это оптимизация для (очень) небольших функций, где затраты на вызов будут значительными. Вы найдете много примеров, например, в windows.pas

Что на самом деле происходит, зависит от сложности функции, общего /частного доступа и вашей версии Delphi.

Другие ответили, что делает inline, но я просто хотел отметить, что есть опция Compiler для включения, выключения или автоматического включения. Проверьте «Процедуры вызова и функции» в D2009 документах для очень хорошего объяснения механики inline. Вот ссылка на онлайн-документы:

Он сообщает компилятору генерировать код для подпрограммы inline; в том месте, где она вызывается, вместо перехода к подпрограмме и обратно.

Для процедур, которые переводятся в очень короткий ассемблер, это может быть преимуществом для производительности, потому что фактический код относительно короткий по сравнению с подготовкой параметра, фактическим вызовом и прологом /эпилогом процедуры.

Если процедура слишком длинная, это может снизить производительность и испортить ваш код.

Он заимствован из C в том смысле, что он сообщает компилятору, что это короткая подпрограмма, которая часто вызывается, и рекомендует, чтобы компилятор рассматривал функцию как макрос и интегрировал код функции непосредственно в программу в вызываемой точке, а не в используйте вызов функции.

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

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

Нажмите Ctrl + Alt + C (все окно отладки ЦП) во время отладки в Delphi перед вызовом встроенной функции. И вы увидите, что встроенные функции запускаются без «вызова» и перехода к другому адресу. Это функция оптимизации.

Блог GunSmoker-а

. when altering one’s mind becomes as easy as programming a computer, what does it mean to be human.

22 декабря 2008 г.

Новое ключевое слово static в Delphi

Недавно я переводил пост Почему методы класса должны быть помечены словом «static», чтобы их можно было использовать в качестве функции обратного вызова? Реймонда Чена. Там я оставил весь код «как есть» — на C++. Здесь я рассмотрю этот вопрос с точки зрения Delphi.

Как известно, в языке есть такие сущности как процедуры/функции и методы. Причём начинающие программисты часто путают эти два понятия.

Функция (в дальнейшем здесь будет также подразумеваться и процедура) — это код. Процедурная переменная — это указатель на код. Например: Метод — это тоже код, но код, связанный с классом. Указатель на метод — это ссылка на код + ссылка на конкретный объект. Например: Когда путают одно с другим компилятор чаще всего показывает такое сообщение: «Incompatible types: regular procedure and method pointer». Чаще всего или забывают писать «of object» в объявлении своих процедурных типов или пытаются передать в функцию (чаще всего как callback — т.е. функцию обратного вызова) метод класса вместо обычной функции (а самым упорным это иногда удаётся).

Что делает эти две сущности такими принципиально несовместимыми? Функция — это просто код. Она не имеет связи с данными, отличными от тех, что передаются в её параметры. Методы класса помимо работы с параметрами (как и обычная функция) ещё могут оперировать с данными объекта (вот оно: «код» vs «код + данные»), например: С функциями такое невозможно — обратите внимание, как вы манипулируете с P3 (он же: Self.P3) в методе. Собственно сам объект (это встроенная переменная Self) неявно передаётся в метод первым параметром. Поэтому, если метод объявлен как function(const P1, P2: Integer): Integer of object — с двумя параметрами, то, на самом деле, он трактуется как функция с тремя параметрами: function(Self: TSomeObj; const P1, P2: Integer): Integer . Именно это различие (на бинарном уровне) делает несовместимыми обычные функции и методы.

Илон Маск рекомендует:  Что такое код pdf_close_image

Соответственно, указатель на обычную функцию — это просто указатель (pointer), только что типизированный (это я про TDoSomethingFunc) — т.е. 4 байта. А вот указатель на метод — это уже запись или, если будет угодно, два указателя — один на код, второй — на данные, т.е. всего 8 байт.

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

Ещё в Delphi есть классовые методы. Это такие методы, которые можно вызывать не имея на руках объект. В этом случае вместо объекта в неявный параметр Self передаётся информация о классе. Т.е. в классовых методах вы не можете использовать информацию о конкретном объекте (например, читать/писать его поля), но можете использовать информацию о классе — например, вызывать конструктор класса. Также методы класса могут быть виртуальными. Заметим, что сигнатура функции, реализующей метод, всё ещё совпадает с сигнатурой обычного метода: неявный параметр (данные класса вместо Self) + все явные параметры метода.

Например: Теперь ещё один шажок и мы переходим к тому, о чём говорил Реймонд Чен. Классовый метод можно объявить статическим (только в новых версиях Delphi). В этом случае у него не будет неявного параметра. Разумеется, при этом он не может использовать информацию экземпляра и класса. Зато он и не отличается от обычной функции.

Рассматривая пример с потоком, вот что мы могли бы написать в старых Delphi без поддержки статических классовых методов: Теперь, с введением нового ключевого слова static, появилась возможность писать так: При этом Реймонд говорит о том, что если у Execute сделать модель вызова stdcall, то бинарные сигнатуры параметра CreateThread, методов ThreadProc и Execute совпадут — поэтому, мол, умный компилятор уменьшит код ThreadProc до простого jmp. Увы, но компилятор Delphi не настолько умён — в этом случае он генерирует полный вызов вместе с передачей параметра.

Каков самый быстрый способ проверить ключевое слово в списке ключевых слов в Delphi?

У меня есть небольшой список ключевых слов. То, что я действительно хотел бы сделать, сродни:

К сожалению, оператор CASE не может использоваться так же, как для строк.

Я мог бы использовать прямую IF, если ELSE IF сконструировать, например:

но я слышал, что это относительно неэффективно.

Вместо этого я сделал следующее:

Это, конечно, не лучший стиль программирования, но он отлично подходит для меня и до сих пор не менял.

Итак, каков наилучший способ переписать это в Delphi, чтобы он был простым, понятным, но и быстрым?

(Для справки, я использую Delphi 2009 с строками Unicode.)

Тоби рекомендовал, чтобы я просто использовал конструкцию If Then Else. Оглядываясь на мои примеры, в которых используется оператор CASE, я вижу, как это жизнеспособный ответ. К сожалению, мое включение CASE непреднамеренно скрыло мой реальный вопрос.

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

Так что действительно хочу знать, есть ли что-то лучше:

Эквивалент If Then Else не выглядит лучше в этом случае:

В комментарии Барри к вопросу Корнеля он упоминает TDictionary Generic. Я еще не нашел новых коллекций Generic, и, похоже, я должен вникать в них. Мой вопрос здесь будет заключаться в том, построены ли они для эффективности и как бы использовать TDictionary для сравнения в взглядах и в скорости для двух вышеперечисленных строк?

В более позднем профилировании я обнаружил, что конкатенация строк как в: (» + MyKeyword + ») ОЧЕНЬ дорогая по времени, и ее следует избегать, когда это возможно. Практически любое другое решение лучше, чем делать это.

В основном я использую функцию IndexText из StrUtils для этой цели. Он похож на ваш подход pos, но возвращаемое значение не зависит от индивидуальной длины строк. В качестве трюка он также нечувствителен к регистру (используйте IndexStr, если вы этого не хотите).

Комментарий к этим функциям фактически упоминает конструкцию случая:

В общем, не используйте строки как «ключи», используйте перечисления — они безопаснее, и вы получаете большую часть увеличения скорости.

К сожалению, Delphi (насколько мне известно) не имеет стандартной реализации хэш-таблицы, которая будет проста в использовании, однако вы всегда можете сворачивать свои собственные.

BTW, code for SEX звучит гораздо веселее, чем «код для пива»: P

Вы можете использовать таблицу const (которая должна быть отсортирована по альфа) и быстрая двоичная сортировка. Он очень эффективен и не требует никакого хеширования.

И вот несколько примеров ключевых слов:

И он очень прост в использовании:

Вы можете легко изменить функцию IsKeyWord(), чтобы вернуть индекс маркера, если вам это нужно.

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

можно заменить на

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

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

является лучшим решением. Ваше собственное решение очень неэлегантное, и для минимального повышения эффективности его не стоит. Конструкция if then else идеально подходит для того, что вы хотите.

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

Один из них — использовать хэш-карту строки, которая похожа на список, индексированный по строкам. Значения в списке будут указателями процедур для кода, который вы хотите выполнить для каждой строки. Все процедуры должны иметь одинаковые точные параметры — и вам придется писать карту хэша самостоятельно или найти тот, который вы можете использовать, например. в JVCL.

Два, и это что-то странное, я пробовал один раз: если и только если строки вашего идентификатора соответствуют 4 символам (как и во всех ваших примерах), и они являются строками ansi (не строки Unicode), вы можете отобразить строки непосредственно к целым числам. 32-разрядное целое эквивалентно по размеру 4-байтовой строке, поэтому вы можете сделать:

Любой строковый идентификатор, длина которого меньше 4 символов, должна быть заполнена пробелами, а строки чувствительны к регистру ( «chil» и «CHIL» дают разные значения). Чтобы использовать это с аргументом case, вам придется предварительно скопировать значения, которые могут быть или не подходят для вашей цели:

И, наконец, вы можете иметь оператор case:

Это код «особого ухода» и может иметь значение только в том случае, если у вас есть сотни или более строк вашего идентификатора — это действительно не должно быть сделано вообще. Конечно, это легко сломать. Я согласен, что утверждения этого случая более быстрые, чем бесконечные шествия блоков. else.

отказ от ответственности: ответ основан на обновленном описании проблемы, т.е. просто проверяет соответствие строки или нет.

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

  • Сколько ключевых слов мы говорим? (какой порядок величины)
  • установлен ли набор ключевых слов?
  • Много ли повторений во входном наборе? (то есть повторяются одни и те же ключевые слова X)
  • Каков ожидаемый коэффициент хита/промаха? Ожидаете ли вы совпадения с одним ключевым словом для каждых тысяч входных слов, или вы ожидаете, что почти каждое слово будет найдено?
  • для небольшого количества ключевых слов (скажем, около 20, в зависимости от реализации), накладные расходы хеширования станут важными.
  • Если вы получите, можете получить идеальную схему хэширования (см. здесь для примера на C), вы можете избавиться от любой цепочки или аналогичную схему, сбрасывая некоторые важные циклы. И снова это потребует, чтобы как ваши ключевые слова, так и набор ввода были известны спереди, что маловероятно.
  • Если в ключевых словах (и большой коллекции хеш файлов) есть много повторений, может помочь небольшой локальный кеш последних X слов.
  • если вы ожидаете много вопиющих промахов (или ваш хеш-алгоритм очень неэффективен; P), trie может быть более эффективным, чем хеш-таблица.

Большинство из них немного экстремальны для обычных задач настройки производительности. Я бы, вероятно, предварительно профилировал стандартные «хешированные» реализации (delphi generics, jcl и т.д.), Чтобы увидеть, какой из них лучше всего подходит для вашей задачи.

Информатизация

Блог о информационных технологиях и не только

вторник, 23 марта 2010 г.

Стилевое оформление исходного кода в Delphi

Естественно переход с собственного стиля оформления на предлагаемый может оказаться непростым, но рано или поздно это надо делать. Есть утилита которая может посодействовать более комфортабельно перейти на этот стандарт. Называется она «delforexp» (Доступна для Delphi 2/3/4/5/6/7/9/2007). В среде Delphi 2010 есть уже встроенный свой инструмент форматирования исходного кода.

Кстати в компании Borland, на Web-сайте компании Borland, на CD, DVD купленных у компании Borland, везде где есть исходный код, стандарт форматирования является законом.

Данный документ не является попыткой определить грамматику языка Object Pascal. В нем приводятся базовые примеры как можно поступить при оформлении исходного кода.

Файлы исходного кода (Наверх) Исходный код Object Pascal подразделяется на модули и файлы проекта, которые подчиняются одинаковым соглашениям. Файл проекта Delphi имеет расширение dpr. Этот файл является главным исходным файлом для всего проекта. Любые модули, используемые в проекте, всегда будут иметь расширение pas. Дополнительные файлы, используемые в проекте могут играть важную роль, но эта глава описывает форматирование только pas и dpr файлов. Более подробно о расширениях файлов можно прочитать в статье: Описание типов файлов в среде Delphi.

Именование файлов (Наверх)
Язык Object Pascal поддерживает длинные имена файлов. Если при создании имени файла Вы используете несколько слов, то необходимо использовать заглавную букву для каждого слова в имени, например: MyFirstProjectName.pas. Такой стиль оформления известен как InfixCaps или CamelCaps. Расширения файлов должны быть в нижнем регистре.

Все файлы модулей которые созданы в какой либо организации, например: ХХХ должны иметь префикс ХХХ

Организация исходных файлов (Наверх)
Все модули Object Pascal могут содержать следующие элементы в определенном порядке:

  • Информация о правах (Copyright/ID);
  • Имя модуля (Unit Name);
  • Секцию интерфейса (Interface section);
    • Подключаемые модули
  • Объявление классов и интерфейсов
    • Дополнительные определения (Additional defines);
  • Реализаця (Implementation)
    • Объявление используемых модулей и директив (Uses clause);
    • Исходный код;
  • Закрывающий оператор и точку (end.) (A closing end and a period).
Илон Маск рекомендует:  Отзывчивый веб-дизайн

Для визуального разделения элементов между ними должна быть хотя бы одна пустая строка.

При создании нового проекта – среда разработки генерирует исходный код, пример которго приведен ниже:

interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;

Нужно заметить что ключевые слова пушиться в нижнем регистре.
Рассмотрим каждые элемент в отдельности:

  • Назначение модуля;
  • Копирайт;
  • Разработчик;
  • Дата последней модификации для исполняемой версии

Он должен выглядеть примерно следующим образом:

Имя модуля (Наверх)
Оно начинается с ключевого слова unit. Имя модуля может содержать символы как в верхнем, так и в нижнем регистре. Например: unit XXXModule1; В результате этот модуль будет назван XXXModule1.pas при сохранении.

Секция интерфейса (Наверх)
Она состоит из определения подключаемых модулей, описания типов, констант, массивов, переменных:

Подключаемые модули(Наверх)
Внутри модуля объявление используемых модулей должно начинаться со слова uses (в нижнем регистре). Затем следуют наименования модулей с сохранением регистра символов.
Каждый используемый модуль должен отделяться от следующего с помощью запятой. Объявление используемых модулей должно заканчиваться точкой с запятой. Список используемых модулей необходимо располагать на следующей строке после слова uses. Если используются модули из разных проектов или производителей, то необходимо сгруппировать модули по проектам или производителям и каждую новую группу начинать с новой строки и прокомментировать каждую группу:

uses
Windows, SysUtils, >// модули Delphi
XХХMyUnit1, ХХXMyUnit2; // модули ХХХ

Если список используемых модулей не умещается по ширине в 80 символов (в редакторе кода есть вертикальная полоса, которая показівает границу в 80 символов), то его необходимо перенести на следующую строку.

Объявление классов, типов и интерфейсов (Наверх)
Для разделения слов нельзя использовать символ подчеркивания. Имя класса должно быть именем существительным или фразой с именем существительным. Имена интерфейсов или классов должны отражать главную цель их создания:

ManageLayout //глагол
delphi_is_new_to_me //подчерк

Объявление класса и типов начинается с двух пробелов, затем идет идентификатор класса(его имя) с префиксом Т.

Следом за идентификатором класса идет пробел, знак равенства, пробел и слово class в нижнем регистре:

TMy > Если необходимо определить родителя класса, то следует добавить открывающую скобку, имя класса — родителя и закрывающую скобку:

TMy > Объявления областей видимости начинаются с двух пробелов и, следовательно, области видимости распологаются на одном уровне с идентификатором класса:

TMy > private
FMyData: Integer;
function GetData: Integer;
procedure SetData(Value: Integer);
public
published
property MyData: Integer read GetData write SetData;
end;

Оформление объявлений интерфейсов подчиняется тем же правилам, что и оформление классов. Отличие будет в использовании ключевых слов специфичных для интерфейсов

Ключевое слово type размещается без отступов, перечисление типов начинается с новой строки:

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;

Реализаця (Implementation) (Наверх)
Может содержать объявление подключенных модулей, дополнительные наборы директив компилятора, исходный код в виде процедур и функция. Например:

Закрывающий оператор и точку (end.) (A closing end and a period) (Наверх)
И конечно же в конце всего этого долен стоять оператор end. – что сведетельствует о окончании модуля.

Соглашение об именовании (Наверх)
Исключая зарезервированные слова и директивы, которые всегда пишутся в нижнем регистре, все идентификаторы Object Pascal должны использовать InfixCaps (Каждое слово начинается с большой буквы):

MyIdentif, MyFTPClass, NewModuleName;

Самое главное исключение для всех правил состоит в использовании оттранслированных заголовочных файлов С/С++. В этом случае всегда используются соглашения, принятые в файле источнике. Например будет использоваться WM_LBUTTONDOWN, а не wm_LButtonDown.

Именование (Наверх)
При именовании полей всегда необходимо использовать InfixCaps. Объявлять переменные только в приватных частях и использовать свойства для доступа к переменным. Для переменных использовать префикс F.

Имена всех локальных переменных должны подчиняться тем же правилам, которые установлены для именования полей, исключая префикс F.

В имени метода всегда должна содержаться команда к действию или глагольная фраза:

ShowStatus
DrawCircle
AddLayoutComponent

MouseButton; //Существительное, не описывает функцию
drawCircle; //Начинается с маленькой буквы
add_layout_component; //Используются символы подчерка
ServerRunning; //Глагольная фраза, но без команды

Обратите внимание на последний пример (ServerRunning) — непонятно, что делает этот метод, он может быть использован как для запуска сервера (лучше использовать StartServer) так и для проверки работы сервера (лучше использовать IsServerRunning).

Имена процедур или методов для установки/получения значений свойств должны составляться по правилу: для получения — Get+имя свойства; для установки — Set+имя свойства.

Методы для теста/проверки булевских свойств класса должны именоваться с префиксом Is+имя свойства.

IsResizable, IsVisible, IsServerRunning;

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

Правильно

Исключение для Венгерской нотации делается в случае объявления перечислимого типа:

TBtnKind = (bkCustom, bkOK, bkCancel, bkHelp,bkYes, bkNo, bkClose, bkAbort, bkRetry,bkIgnore, bkAll);

bk обозначает ButtonKind;

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

Переменные цикла именуются I и J. Другие случаи использования однобуквенных переменных это S (строка) и R (результат). Однобуквенные имена должны всегда использовать символ в верхнем регистре, но лучше использовать боле значимые имена. Также не рекомендуется использовать переменную l (эль), потому что она похожа на 1 (единица).

Зарезервированные слова (Наверх)
Зарезервированные слова и директивы должны быть все в нижнем регистре. Производные типы должны начинаться с большой буквы (Integer), однако string — это зарезервированное слово и оно должно быть в нижнем регистре.

Использование пустых строк (Наверх)
Пустые строки могут повысить читабельность путем группирования секций кода, которые логически связаны между собой. Пустые строки должны использоваться в следующих местах:

  • После блока копирайта;
  • После декларации пакета;
  • После секции импорта;
  • Между объявлениями классов;
  • Между реализациями методов;

Использование пробелов(Наверх)
Язык Object Pascal является очень легким для понимания языком, поэтому нет особой необходимости в использовании большого количества пробелов. Следующие пункты дадут Вам понимание — в каком случае необходимо использовать пробелы.

Пробелы, запрещенные к использованию в следующих случаях:

  • До или после оператора .(точка);
  • Между именем метода и открывающей скобкой;
  • Между унарным оператором и его операндом;
  • Между выражением приведения (cast) и приводимым выражением;
  • После открывающей скобки или перед закрывающей;
  • После открывающей квадратной скобки [ или перед закрывающей ];
  • Перед точкой с запятой;

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

function TMyClass.MyFunc(var Value: Integer);
MyPointer := @MyRecord;
My > MyInteger := MyIntegerArray[5];

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

function TMyClass.MyFunc( var Value: Integer ) ;
MyPointer := @ MyRecord;
My > MyInteger := MyIntegerArray [ 5 ] ;

Использование отступов (Наверх)
Всегда необходимо использовать два пробела для всех уровней отступа. Другими словами, первый уровень отступает на два пробела, второй на четыре и так далее. Можно настроить табуляцию на ширину в 2 пробела и пользоваться табуляцией.

Существует несколько исключений из этого правила. Зарезервированные слова unit, uses, type, interface, implementation, initialization и finalization, они всегда должны примыкать к левой границе.

Также должны быть отформатированы финальные end-ы , завершающий исходный модуль и отдельные блоки. В файле проекта выравнивание по левой границе применяется к также к словам program, главным begin и end. Код внутри блока beginend должен иметь отступ два символа.

Перенос строк (Наверх)
Все строки должны быть ограничены 80 столбцами. Строки, длиннее чем 80 столбцов должны быть разделены и перенесены. Все перенесенные строки должны быть выровнены по первой строке и иметь отступ в два символа. Выражение begin всегда должно находиться на своей отдельной строке.
Никогда не разрывайте строку между параметром и его типом, кроме параметров, перечисляемых через запятую. Двоеточие для всех объявлений переменных не должно содержать перед собой пробелов и иметь один пробел после перед именем типа.

procedure Foo(Param1: Integer; Param2: Integer);

procedure Foo( Param :Integer; Param2:Integer );

Нельзя переносить строки в тех местах, где не допускаются пробелы, например между именем метода и открывающей скобкой или между именем массива и открывающей квадратной скобкой. Никогда нельзя помещать выражение begin на строку, содержащую другой код.

while (LongExpression1 or LongExpression2) do begin
// DoSomething

В случае с логическими операторами предпочтительнее будет следующий вариант:

Комментарии (Наверх)
Язык Object Pascal поддерживает два типа комментариев: блочные и однострочные. Общие правила по использованию комментариев могут быть следующими:

  • Помещайте комментарий недалеко от начала модуля для пояснения его назначения;
  • Помещайте комментарий перед объявлением класса;
  • Помещайте комментарий перед объявлением метода;
  • Избегайте очевидных комментариев: (i := i + 1 // добавить к i единицу);
  • Помните, что вводящий в заблуждение комментарий хуже чем его отсутствие;
  • Избегайте помещать в комментарий информацию, которая со временем может быть не верна;
  • Избегайте разукрашивать комментарии звездочками или другими символами;
  • Для временных (отсутствующие в релизе) комментариев используйте «TODO«.

Блочные комментарии(Наверх)
Object Pascal поддерживает два типа блочных комментариев. Наиболее часто используемый блочный комментарий — это пара фигурных скобок: . Команда разработчиков Delphi предпочитает использовать этот комментарий как можно проще и как запасной. Используйте в таких комментариях пробелы для форматирования текста и не используйте символы зведочка «*». При переносе строк необходимо сохранять отступы и выравнивание

Каков самый быстрый способ проверить ключевое слово в списке ключевых слов в Delphi?

У меня есть небольшой список ключевых слов. То, что я действительно хотел бы сделать, сродни:

К сожалению, оператор CASE не может использоваться так же, как для строк.

Я мог бы использовать прямую IF THEN ELSE IF, например:

но я слышал, что это относительно неэффективно.

Вместо этого я сделал следующее:

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

Итак, каков наилучший способ переписать это в Delphi, чтобы он был простым, понятным, но также быстрым?

(Для справки, я использую Delphi 2009 с строками Unicode.)

Тоби рекомендовал, чтобы я просто использовал конструкцию If Then Else. Оглядываясь на мои примеры, в которых используется оператор CASE, я вижу, как это жизнеспособный ответ. К сожалению, мое включение CASE непреднамеренно скрыло мой реальный вопрос.

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

Поэтому я действительно хочу знать, есть ли что-то лучше, чем:

Эквивалент If Then Else не выглядит лучше в этом случае:

В комментарии Барри к вопросу Корнеля он упоминает TDictionary Generic. Я еще не нашел новых коллекций Generic, и, похоже, я должен вникать в них. Мой вопрос здесь будет заключаться в том, построены ли они для эффективности и как использовать TDictionary для сравнения в взглядах и в скорости для двух вышеперечисленных строк?

В более позднем профилировании я обнаружил, что конкатенация строк как: (» + MyKeyword + ») ОЧЕНЬ дорогая по времени, и ее следует избегать, когда это возможно. Практически любое другое решение лучше, чем это делать.

[Delphi] Как сделать поиск точного слова ?

Что касается вопроса, то можно попробовать сделать, например, так

Find := Edit1.Text; // текст для поиска
i := 1; // начальная позиция поиска
while PosEx(Find, Memo1.Lines.Text, i) <> 0 do begin
i := PosEx(Find, Memo1.Lines.Text, i);
// здесь i содержит позицию очередного вхождения подстроки в текст
// и можно делать с ней все, что угодно, например, «записать в переменную»
i := i + 1; // смещаем позицию
end;

Если вас интересуют строки, на которых расположены искомые подстроки, то в цикле по строкам мемо ищите нужный фрагмент.

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL