AppleScript для абсолютных новичков

Дата публикации:18.07.2012
Поделиться в Twitter Поделиться в F******k Поделиться в VKontakte Поделиться в Telegram Поделиться в Mastodon

Глава 13. Циклы

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

Если вам известно, какое число раз должен повториться оператор (или группа операторов), вы можете указать его, включив это число в оператор repeat сценария [1]. Число должно быть целым, потому что вы не можете повторить какую-либо операцию, скажем, 2,7 раза.

repeat 2 times
say "Julia is a beautiful actress"	[1]
end repeat
say "This sentence is spoken only once"

Аналогично тому, что мы видели для операторов "tell", "try" и "if...then", оператор "end repeat" обязателен, чтобы показать AppleScript'у какие операторы принадлежат к группе повторяющихся операторов.

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

set repetitions to 2
repeat repetitions times
-- Здесь следуют повторяемые операторы	[2]
end repeat

В сценарии [3] более похожая на действительность модификация сценария [2]. Когда сценарий [3] запущен, пользователю предлагается ввести число в диалоговое окно. Поскольку все что будет введено в итоге окажется в "text returned", мы должны конвертировать введенное значение в целое число. Такую конвертацию будет невозможно выполнить, если пользователь введет текст или действительное (дробное) число. Так что, мы должны принять некоторые меры предосторожности.

-- Пользователю предлагается задать количество раз произнесения текстовой
строки
set textToDisplay to "How often has the sentence to be repeated?"
-- Число "2" будет показано, чтобы намекнуть пользователю, какой тип данных
ожидается
display dialog textToDisplay default answer "2"
set valueEntered to text returned of the result
try
-- valueEntered это строка (не целое), которое может выглядеть так: "2".
-- Здесь мы попытаемся преобразовать введенное пользователем значение в целое. Если это не получится, то оператор try предотвратит прерывание сценария.
set valueEntered to valueEntered as integer	[3]
end try
-- Если valueEntered будет соответствующего класса (т.е. целым) мы сможем выполнить блок цикла. Если нет, мы покажем диалоговое окно.
if class of valueEntered is integer then
-- Блок цикла выполнится, если не произойдет сбоя при преобразовании
repeat valueEntered times
say "Julia is a beautiful actress"
end repeat
else
display dialog "You did not enter a (valid) number."
end if

После оператора else [3.21], пользователя сценария упрекнут, что он не использовал подсказку о том как сделать правильно, и пользователь должен будет заново запустить сценарий. Такая манера поведения программы не особенно то приветствуется в среде Мак-сообщества. Вот два альтернативных оператора repeat [4, 5], которые позволят вам повторять операции до тех пор пока условие не выполнится.

set conditionMet to false
repeat while conditionMet is false
-- если (некоторая проверка даст в результате истину),
-- то выполните следующий оператор	[4]
--   set conditionMet в true
end repeat
set conditionMet to false
repeat until conditionMet is true
-- если (некоторая проверка даст в результате истину),
-- то выполните следующий оператор	[5]
--   set conditionMet в true
end repeat

Давайте используем оператор repeat сценария [4] для того чтобы устранить неудобство сценария [3]. Мы будем повторять запрос до тех пор, пока введенное значение не преобразуется в целое. В случае удачного преобразования, мы установим переменную "correctEntry" на true, в результате чего петля цикла будет покинута, и произнесение фразы сценария будет выполнено [6]. Если значение введенное пользователем невозможно будет преобразовать в целое, то мы дадим пользователю детализированную обратную связь.

set correctEntry to false
repeat while correctEntry is false
-- Пользователю предлагается задать количество раз произнесения текстовой строки
set textToDisplay to "How often has the sentence to be repeated?"
-- Число "2" будет показано, чтобы намекнуть пользователю, какой тип данных ожидается
display dialog textToDisplay default answer "2"
set valueEntered to text returned of the result
try
-- valueEntered всегда строка.
-- Здесь мы попытаемся преобразовать введенное пользователем значение в целое.
-- Если этого не случится, мы перепрыгнем в секцию on error
set valueEntered to valueEntered as integer
-- Установка correctEntry на true закончит цикл
set correctEntry to true
on error
-- Создадим детализированную обратную связь	[6]
try
-- Сначала мы проверим, вдруг пользователь ввел дробь
set valueEntered to valueEntered as number
display dialog "You entered a fractional number instead of an integer."
on error
-- Если это не число, введенное должно быть текст
display dialog "Instead of an integer, like 9, you entered text."
end try
-- Так как значение correctEntry осталось ложным, цикл продолжается
end try
end repeat
-- Сценарий может выполнить следующие операторы, только если correctEntry будет истинным.
-- с orrectEntry будет истинным только если valueEntered удачно преобразуется в целое
repeat valueEntered times
say "Julia is a beautiful actress"
end repeat

Обратите внимание на то, где расположен оператор "set correctEntry to true", это очень важно. Его положение должно быть: - внутри (первого) блока try; и

- после оператора, который может привести к ошибке (попытка преобразования - потенциально опасный оператор).

Иначе correctEntry станет истинным независимо от того требуемое ли действие (успешное преобразование в целое) выполнится.

Несмотря на то, что сценарий [3] может выполнить заданное действие (произнести фразу указанное количество раз) в точности как сценарий [6], он не является ни дружественным для пользователя, ни надежным. Т.е. в нем произойдет сбой, если пользователь введет неверные данные, и он не сможет обеспечить адекватную реакцию, если пользователь сделает ошибку. Сценарий [6] можно улучшить путем введения ограничения на значение valueEntered (например, используя фрагмент [7]), чтобы предотвратить произнесение фразы 10,000 раз. С другой стороны, может и сценарий [6] вполне удовлетворит ваши потребности.

if valueEntered > 5 then
set valueEntered to 5	[7]
end if

Если вам нужен действительно надежный сценарий, вы должны его хорошенько протестировать. Попробуйте ввести текст, дробные числа, очень большие числа и т.п., чтобы проверить как сценарий себя поведет. Единственное, что не предусмотрено сценарием [6], это тот случай, когда пользователь введет отрицательное число. Вы можете тоже перевести его в положительное число, или просто сообщить пользователю, что ожидается положительное число. Интересно, что в сценарии [6] не произойдет сбоя, если ввести отрицательное число. Проверьте это сами изменив сценарий [1].

Операторы repeat сценариев [4] и [5] легко могут быть использованы для любой цели. Вы можете выполнять цикл, чтобы убедиться в том, что: - пользователь выбрал файл или папку, - слово присутствует в файле, - в программе выделен нужный объект, - и т.п.

В противоположность основному применению операторов repeat в сценариях [4] и [5], сценарии [1] и [2] предназначены для числовых условий. Для этого существует еще несколько операторов repeat.

repeat with counter from 1 to 5
say "I drank " & counter & " bottles of coke."	[8]
end repeat

Вы можете использовать переменную оператора [8.1], т.е. "counter", в вашем сценарии. Однако, вы не сможете изменить значение переменной внутри блока repeat.

repeat with counter from 1 to 5
say "I drank " & counter & " bottles of coke."	[9]
set counter to counter + 1
end repeat

Если вы запустите сценарий, ни одной произносимой фразы не будет пропущено, и все бутылки - с 1 по 5 - будут выпиты.

В операторе [9.1] шаг размером равным 1 используется по умолчанию. Если вы хотите другой размер шага, вы можете его задать - [10.1].

repeat with counter from 1 to 5 by 2
say "I drank " & counter & " bottles of coke."	[10]
end repeat

В сценарии [10] используется шаг с размером равным 2. Вы услышите предложение три раза (при значениях счетчика равных 1, 3 и 5).

Если у вас есть список, и каждый элемент должен быть использован в какой либо операции, вы можете подсчитать число элементов в списке, и выполнить цикл repeat как в сценарии [11].

tell application "Finder"
set refToParentFolder to alias "Macintosh HD:Users:ik:Documents:"
set listOfFolders to every folder of refToParentFolder	[11]
set noOfFolders to the count of y
repeat with counter from 1 to noOfFolders
-- Здесь действия
end repeat
end tell

В AppleScript есть элегантная альтернатива, демонстрация которой дается ниже. Сценарий [12] позволяет вам определить количество вложенных папок в выбранной пользователем папке. Затем оператор repeat создает список имен всех имеющихся папок.

set folderSelected to choose folder "Select a folder"
-- Чтобы отыскать все имеющиеся папки в выбранной папке,
-- мы просим Finder дать нам ответ.
-- Внимание: "every folder" НЕ включает папки,
-- находящиеся внутри других папок.
-- Это просто папки, которые вы увидите как если бы открыли папку в Finder.
tell application "Finder"
set listOfFolders to every folder of folderSelected
end tell
-- Результат будет списком ссылок на папки (путей),
-- которые могут быть обработаны вне блока обращения Finder.
-- Закоментируйте все последующие операторы и используйте поле результата,
-- чтобы увидеть, что список "listOfFolders" содержит нечто вот такое:
-- folder "reports" of folder "Documents" of folder "ik" of folder "Users" of startup disk of application "Finder".
-- Только Finder и AppleScript (компонент Mac OS X) умеют обращаться с такими ссылками.
-- Имена папок будут сохранены в новом списке, который создается здесь
set theList to {}
repeat with aFolder in listOfFolders
-- Мы имеем ссылки на папки, и так как ссылка содержат имя папки,
-- AppleScript (компонент Mac OS X) может добыть имя не обращаясь к Finder.
-- Если же вы хотите получить другое свойство папки, например размер (size, в байтах) папки,
-- придется столкнуться с Finder (и также понадобиться блок обращения для следующего оператора).
set temp to the name of aFolder
-- Здесь мы добавляем имя в список.
set theList to theList & temp
end repeat

Дополнительная информация

  1. Полный вариант книги (rtf/7z)-- электронная книга с сохранением иллюстраций, форматирования, изменений в цвете шрифта.


Распространение материалов сайта означает, что распространитель принял условия лицензионного соглашения.
Идея и реализация: © Владимир Довыденков и Анатолий Камынин,  2004-2024