Поиск в Delphi. Часть 1: Регулярные выражения |
- Statistics
- Participants
- Translate into Russian
- Translation result
- Translated in draft, editing and proof-reading required. Completed: 15%.
Возможность быстро и легко найти что-то в своем коде очень важна для любой IDE. Проводя слишком много времени в поисках чего-то Вы теряете свои мысли. На протяжении многих лет Delphi представлял множество различных способов поиска в Вашем коде, некоторые из них - простое текстовое соответствие, другие намного более мощные поисковые системы, способные понимать структуру Вашего кода. Как бы то ни было, я постоянно встречаю разработчиков, которые не знают о многих из них, разве что только о простом поиске с использованием пункта меню Search | Find (Ctrl-F) , или же о поиске по нескольким файлам с помощью Search | Find in Files (Shift-Ctrl-F).
Начинаясь с этого поста я собираюсь попробовать и обратиться к части этого. Каждое сообщение будет посвящено различным способам, чтобы найти то что вам надо в вашем проекте. Я буду считать, однако, что каждый может использовать просто средства Find и Find in Files, поэтому я не буду рассматривать это. Тем не менее, я начну с рассмотрения одной возможности обоих этих средств поиска, которые недостаточно используются - это регулярные выражения.
При выполнении текстового поиска, как правило, чем конкретнее вы зададите строку поиска, тем меньше ложных совпадений вы получите (т.е. совпадения, которые вы на самом деле не ищете) . Проблема в том, что Вы часто либо не знаете, насколько точно совпадает введенный текст с искомой строкой, либо Вы пытаетесь найти соответствие нескольким строкам с разным текстом рядом с вашей строки. Таким образом, вы в имеете не очень конкретную строку поиска, и множество совпадений на которые вы тратите кучу времени, пытаясь найти соответствующие искомому, или что еще хуже, пропустить некоторые важные среди этого множества.
Возможно, вы никогда не получите безупречный результат, содержащий только то, что вы ищете. Это заканчивается компромиссом между временем на создание строки поиска и временем на поиск по результатам, и часто достаточно сбалансировано, достаточно хорошо. Это то, где регулярные выражения могут помочь
Позвольте мне привести вам конкретный пример.
Фреймворк DUnit интенсивно использует интерфейс, который называется ITest. Допустим, вы хотите найти все места, где в TestFramework.pas ITest передается в качестве параметра метода.
Начнем, нажмем Ctrl-F, введем ITest и нажмем Enter и, как вы можете увидеть на картинке слева, мы получим 143 результата только для этой одной строки.
Как вы могли заметить, имеется целый набор результатов, которые фактически не являются тем, что мы искали. Это соответствие ITestDecorator, ITestListener, даже комментарии. Более того, найдены все совпадения с ITest, а не только те, где ITest использован в качестве параметра метода
Итак, как мы можем попытаться ограничить результаты поиска? Мы могли бы попытаться искать ": ITest", и это дает нам меньше результатов, но она все еще есть проблемы. Во-первых, они упускают из виду места, где нет пробела между двоеточием и ITest. Также будут ложные совпадения в местах объявления переменных типа ITest. Мы могли бы искать строку ": ITest)", которая удаляет поля и объявления переменной, но так мы потеряем совпадения, когда имеются дополнительные параметры в описании метода после параметра ITest. Более того, а если параметр - массив из ITest? Мы пропустим их не найдем.
Хорошо, теперь, что моё чучело надлежаще установлено, подумайте о том, как мы можем более точно определить только ITest-параметры метода. Может быть, если мы будем искать двоеточие, за которым следуем ноль или более символов, далее ITest, после которого также следуют ноль или более символов и закрывающая скобка.
Я далеко не эксперт по регулярным выражениям, я могу довольно легко помнить 3 или 4 элемента синтаксиса, не заглядывая в справочник. Тем не менее, даже эти немногие из них могут быть довольно мощным. В самом деле, в этом примере мне необходимо помнить только три вещи, чтобы задать мой поиск:
* Точка или символ разделения разрядов в регулярном выражении соответствует любому одиночному символу (за исключением символа перевода каретки). Таким c.t будет соответствовать cat и cut, но не cart.
* Знаком звездочки в регулярных выражениях означается соответствие предыдущему знаку ноль или более раз. T * будет соответствовать TT, TTT и т.д. Более того, вы можете использовать их вместе, .* что любой символ встречается ноли или более раз. Потому c.*t будет соответствовать cat, cut, а также cart.
* И наконец, вам экранируете символы, которые имеют специальное значение в регулярных выражениях (такие как звездочка и точка) с помощью обратной косой черты "\". Допустим, вы действительно хотите найти точку, значит вам нужно записать это так \.
Это почти все, что я помню о регулярных выражениях, но этого достаточно для хорошего поиска.
Вернемся к примеру. Я говорил, что хочу найти:
1. двоеточие
2. за которым следует ноль или более символов
3. затем ITest
4. за которым следует ноль или более символов
5. затем закрывающая скобка
На основании того, что мы только что обсуждали, регулярное выражение для каждого из вышеперечисленных условий будет выглядеть так:
1. :
2. .*
3. ITest
4. .*
5. \)
Заметьте, я должен был экранировать закрывающую скобку, так как это спецсимвол в регулярном выражении (я только что посмотрел, так как я не помню, для чего она нужна. Она используется для объединения нескольких знаков)
Завершенное регулярное выражение выглядит так :.*ITest.*\)
Чтобы его использовать, вам необходимо разрешить регулярные выражения при поиске. На картинке выше это не показано, но если вы сделаете ваше окно редактирования достаточно широким (или нажмите на>> изображения рядом с Case Sensitive), вы получите возможность использовать регулярные выражения. (до 2010 Delphi это флажок в модальном диалоговом который появляется, когда вы нажимаете Ctrl-F). Затем просто наберите: .* ITest .* \) в этом же окне поиска, как вы обычно это делаете.
Теперь мы получили значительно меньше результатов (около половины). Это не очень хорошо, но это и не было моей целью. Я не стремился к совершенным результатам поиска. В этом примере я насчитал 4 ложных совпадения (до сих пор находятся параметры начинающиеся с ITest, такие, как ITestListener), но, кажется, это удовлетворяет приведенным условиям, и 69 из 73 это гораздо лучше, чем 69 из 143.
Я не мог избавиться от сомнений, что остались ложные соответствия, и если вами интересно проверить, то есть хороший справочник по регулярным выражениям, а также учебное пособие http://www.regular-expressions.info. Там также есть описание поддерживаемого средой синтаксиса регулярных выражений. Как бы то ни было, я получил очень хороший компромисс между результатами и объемом работы. Я часто замечаю, если я попытаюсь сделать мои регулярные выражения слишком сложными, я начинаю тратить больше времени на подбор строки поиска, чем на просмотр результатов. Однако, может быть это просто таковы мои знания синтаксиса регулярных выражений.
Как часто я могу использовать регулярные выражения для поиска? Честно говоря, не часто. Однако, это одна из тех вещей, овладев которой однажды, вы будете использовать её чаще. В следующий раз, когда вы будете что-то искать, и результат не удовлетворит вас, может быть, стоит использовать эту возможность. Я замечаю, что в таких случаях я могу найти то, что я ищу гораздо быстрее и точнее затратив меньше усилий, чем в других случаях.
Далее, я рассмотрю некоторые другие, менее известные возможности поиска по коду.
Original (English): Searching in Delphi Part 1 : Regular Expressions
