Вы можете найти рассылки сходной тематики в Каталоге рассылок.
В рассылке используются материалы веб-сайта
www.spsstools.ru
Содержание выпускаО некоторых особенностях обработки строковых значений Новое на сайте www.spsstools.ru Здравствуйте, уважаемые подписчики! С мая 2006 года сервис Subscribe.Ru предоставляет получателям HTML-версий рассылок возможность голосования за очередной выпуск (через сайт, либо письмом). В нижнем и верхнем колонтитулах каждого выпуска вы найдёте шкалу для голосования по 5-балльной шкале (где 5 означает наивысший балл). Я просил бы вас по возможности выражать своё мнение относительно содержания, оформления, стиля, полезности полученного вами выпуска в виде этой комплексной оценки. Развёрнутые комментарии вы всегда можете направить мне на a-balabanov( at) yandex.ru.
О некоторых особенностях обработки строковых значенийКазалось бы, уже многое сказано о работе со строковыми значениями в SPSS, в том числе и в рамках данной рассылки. Но в недрах коллекции Рейналя отыскиваются всё новые и новые оригинальные, нестандартные примеры работы со строками, достойные подробного изучения. Рассмотрим очень короткий, но ёмкий синтаксис, на примере которого демонстрируются два независимых друг от друга приёма программирования в SPSS: - возможность преобразования ASCII-кода символа в сам символ; - простой способ замещения отдельных символов в строке. Вот как звучал исходный вопрос, заданный однажды в новостную группу SPSS: "У меня есть строковая переменная, содержащая числа. Фактически, это ASCII-коды символов (в парах цифр). Например, первое наблюдение внизу 79 80 69 78 и т.д., фактически означает символы "OPEN". Как мне преобразовать коды в символы?". К вопросу прилагаются данные - два наблюдения, содержащие закодированные строки: DATA LIST /mystr (A30). BEGIN DATA. END DATA. Автор ответа: Bjarte Aagnes, дата ответа: 27.02.2002. Несмотря на то, что описанная в вопросе ситуация может и не случиться в вашей практике, синтаксис, составленный Bjarte демонстрирует интересные идеи, которые можно при случае использовать в той или иной модификации. Для начала напомним, что ASCII-коды - это таблица из 256 кодов со значениями 0-255, каждому из которых поставлен в соответствие некоторый текстовый символ. Выбор числа 256 не случаен - именно такое количество разных кодов можно составить, комбинируя единицы и нули в последовательности по 8 разрядов (т.е. в пределах одного байта). Это - важное замечание, так как далее мы будем оперировать специальным форматом для извлечения текстовых значений, соответствующих кодам. Обычно таблица ASCII включает постоянную и переменную часть. В постоянной части находятся управляющие, невидимые символы (включая символ "возврата строки" и "перевода каретки", пробел), цифры от 0 до 9, буквы латиницы от A До z и некоторые другие символы. Переменная часть может подвергаться локализации и, в зависимости от установленной версии кодировочной таблицы, она может содержать, например, буквы кириллицы. Да, впрочем, что выдумывать определения. Вот что говорит справочная система Windows XP про ASCII: "Однобайтная кодировка, используемая для представления в компьютере текстовых данных. Семи- или восьмибитная таблица ASCII позволяет закодировать 128 или 256 разных знаков. Стандартная кодировка ASCII использует 7 битов для представления всех прописных и строчных букв, чисел от 0 до 9, знаков препинания и специальных управляющих символов, применяемых в английской раскладке для США. Современные системы на базе процессоров x86 поддерживают расширенную кодировку ASCII. Расширенная кодировка использует восьмой бит каждого кода для представления 128 дополнительных специальных символов, букв различных алфавитов и графических знаков." В современных системах широко применяется и более "продвинутая" кодировка Unicode, однако сейчас речь о ней не идёт. В данном случае в распоряжении автора вопроса были "усечённые" коды ASCII, пары цифр от 00 до 99, что достаточно для отображения заглавных букв латиницы.
Идея решения Зная, что код каждого символа задаётся парой значений, будем последовательно "отщипывать" из строки с кодами по 2 цифры как текстовые значения, преобразовывать выделенную пару цифр в число, а затем полученное число - вновь в текстовый символ, указывая, однако, что данное число - это реализация двоичного представления кода символа. Это делается с использованием специального двоичного формата: PIB - positive integer binary. Полученный символ заменяет соответствующую пару символов, содержащих числовой код в исходной строке.
Программная реализация Очевидно, что нам придётся "пробегать" по всем символам строчки кодов для того, чтобы преобразовать каждый код в текст. Для этой цели идеально подходит цикл LOOP - END LOOP и текстовая функция SUB (или SUBSTRING), выделяющая из текстовой строки подстроки заданной длины, начиная с определённого символа. Чтобы в ходе выполнения цикла не создавались лишние переменные, автор решения использует временные, скрытые переменные (с префиксом #). В данном случае индекс цикла #pos пробегает значения от 1 до 30 (поскольку длина строки известна из описания переменной - 30 символов) с шагом 2 (дополнительная спецификация "by 2"). Шаг 2 - потому, что код задаётся парой значений. Если бы ASCII-кодами кодировались символы кириллицы, подтребовалось бы представление каждого кода 3 цифрами, тогда имело бы смысл шагом цикла сделать 3 с аналогичными изменениями далее по алгоритму. Кроме этого, в цикле используется вспомогательный индекс #adj. Перед началом цикла мы обнуляем его для каждого наблюдения инструкцией COMP (тожд. COMPUTE) #adj = 0, а затем - в теле цикла для каждого наблюдения наращиваем от нуля и выше "вручную", инструкцией COMP #adj = #ad j+ 1 (в то время как индекс #pos, являясь элементом цикла, наращивается автоматически). Рассмотрим, что содержательного происходит с каждым наблюдением при первом выполнении цикла. Переменные #adj = 0, #pos = 1. Посмотрим на правую часть выражения COMP[ute], стоящего после LOOP. Раскроем скобки, начиная с середины. Функцией SUB мы выделяем из строки (переменной mystr, содержащей коды) первый код (пару символов). Подстрока начинается с первого символа (#pos = 1) и имеет длину, равную 2. Затем эту пару цифр в текстовом представлении мы преобразуем в число формата N2. Это особый формат, не допускающий знака и не содержащий в своей записи каких-либо знаков, кроме цифр. Незначащие нули в начале числа сохраняются. Иными словами, текстовая запись кода "01" будет представлена в числовом формате N2 как 01. Такой формат в данном случае является более "понятным" пользователю (код сохраняется в первозданном виде), но, строго говоря, все равно какой тип числового формата использовать: главное - "объяснить" машине, что она считала целое число без знака и десятичной точки. Далее - ключевой момент. Функцией STRING мы преобразуем полученное числовое значение в соответствующий текстовый символ, используя при этом не обычный числовой формат, например, F2.0, а формат PIB1, указывающий, что подлежащее преобразованию число является десятичным представлением однобайтного кода. Тогда значением функции STRING будет текстовый символ из таблицы ASCII, соответствующий этому коду. Хорошо, с преобразованием закончили. Не менее любопытной представляется левая часть выражения COMP[ute]. Мы привыкли, что слева от знака равенства должно быть указано имя переменной. Однако в данном случае здесь стоит функция SUB[string]. Кажется, это единственная функция, которая по логике своей может находиться слева от знака присваивания. Вместо того, чтобы создавать дополнительную переменную с результатом перекодировки, мы можем заменять значение прямо в текущей строковой переменной. Выделяемая функцией SUB подстрока заменяется результатом выражения справа от знака равенства. Вообще, таким образом можно легко избирательно заменять те или иные символы в строковой переменной, избавляясь от необходимости создания дополнительной переменной, комбинирования команд конкатенации, удаления исходной переменной и переименования вспомогательной. В данном случае, однако же, есть некоторая сложность. Связана она с тем, что мы преобразуем код из 2 цифр в один текстовый символ. Если при этом мы будем заменять две цифры на 1 символ, смысловая часть строки будет "укорачиваться", а идущий вперёд индекс цикла будет ошибочно выбирать для перекодирования ненужные коды. Чтобы обойти указанную трудность нам и потребовался вспомогательный индекс #adj, разность которого с индексом #pos (#pos - #adj) даёт последовательность чисел 1, 2, 3, ... Таким образом, не важно, код какой длины мы преобразуем: замена производится посимвольно, начиная с первого. Казалось бы, при таком подходе в переменной должна оставаться часть исходных кодов, которые не были заменены. Однако, если в строке формата A30 хотя бы последний, 30-й символ окажется незаполненным (это будет автоматически подставленный программой пробел), преобразование этого символа в число даст пропущенное значение, которое будет затем интерпретировано форматом PIB как код "0", что соответствует пустой строке. Таким образом, все незамещённые к этому моменту коды будут просто затёрты. Обратите внимание, что в указанном примере SPSS будет несколько раз выдавать предупреждения в окне результатов, связанные с тем, что производится попытка преобразовать пробелы в число. COMP #adj=0. LOOP #pos = 1 TO 30 by 2. COMP SUB(mystr,#pos-#adj,1)=STRING(NUMBER(SUB(mystr,#pos,2),N2),PIB1). COMP #adj=#adj+1. END LOOP. LIST. Команда LIST запускает все отложенные вычисления и выводит их результат. Напоследок. Попробуйте задать для какой-нибудь числовой переменной (varnum, например) двоичный формат. Допустим, двухбайтный PIB2. FORMATS varnum (PIB2). В редакторе данных в столбце для этой переменной станут отображаться текстовые строки, соответствующие числовым значениям, интерпретированным как ASCII-коды. Если при этом вы введёте в переменную какой-либо символ, в переменной будет сохраняться его ASCII-код. Немного сложнее ситуация с тем, когда в переменной содержится большое числовое значение, либо несколько символов. Результирующий код будет десятичным представлением последовательности байтов. Например, отдельно символы "0" и "е" получат коды 48 и 101, соответственно. Однако, будучи введёнными вместе, как строка "0e", они дадут результирующий код 25904, что является десятичным представлением последовательности битов 01100101 (т.е. 101) и 00110000 (т.е. 48): 0110010100110000 (bin) = 25904 (dec).
Всего доброго!
Ведущий рассылки, Балабанов Антон Новое на сайте www.spsstools.ruПереведены и добавлены примеры синтаксиса: Взвешивание по 2 и более переменным.SPS Удаление меток множества переменных.SPS Группировка данных и создание соответствующих меток (категоризация).sps Объединить файл описанных переменных и файл данных.SPS Вывести метки переменных и значений в одной и той же частотной таблице.SPS
© См. www.spsstools.ru, 2005-2006 |
В избранное | ||