Описание библиотеки Haskell 98: Утилиты работы с символами Описание Haskell 98
наверх | назад | вперед | содержание | предметный указатель функций

19  Утилиты работы с символами


module Char ( 
    isAscii, isLatin1, isControl, isPrint, isSpace, isUpper, isLower, 
    isAlpha, isDigit, isOctDigit, isHexDigit, isAlphaNum, 
    digitToInt, intToDigit,
    toUpper, toLower,
    ord, chr,
    readLitChar, showLitChar, lexLitChar,

-- ...и то, что экспортирует Prelude
    Char, String
    ) where

isAscii, isLatin1, isControl, isPrint, isSpace, isUpper, isLower, 
 isAlpha, isDigit, isOctDigit, isHexDigit, isAlphaNum :: Char -> Bool

toUpper, toLower        :: Char -> Char

digitToInt :: Char -> Int
intToDigit :: Int -> Char

ord        :: Char -> Int
chr        :: Int  -> Char

lexLitChar  :: ReadS String
readLitChar :: ReadS Char
showLitChar :: Char -> ShowS

Эта библиотека предоставляет ограниченный набор операций над символами Unicode. Первые 128 элементов этого набора символов идентичны набору символов ASCII; следующие 128 элементов образуют остаток набора символов Latin 1. Этот модуль предлагает только ограниченное представление полного набора символов Unicode; полный набор атрибутов символов Unicode в этой библиотеке недоступен.

Символы Unicode можно разделить на пять общих категорий: непечатаемые символы, строчные алфавитные символы, остальные алфавитные символы, числовые цифры и остальные печатаемые символы. В Haskell любой алфавитный символ, который не является строчной буквой, рассматривается как заглавный символ (верхнего регистра) (Unicode на самом деле имеет три регистра: верхний, нижний и заглавный). Числовые цифры могут являться частью идентификаторов, но цифры вне диапазона ASCII не должны использоваться читателем для обозначения чисел.

Для каждого вида символов Unicode выполняются следующие предикаты, которые возвращают True:

Тип символов Предикаты
Строчные алфавитные символы isPrint isAlphaNum isAlpha isLower
Остальные алфавитные символы isPrint isAlphaNum isAlpha isUpper
Цифры isPrint isAlphaNum
Остальные печатаемые символы isPrint
Непечатаемые символы

Функции isDigit, isOctDigit и isHexDigit выбирают только символы ASCII. intToDigit и digitToInt осуществляют преобразование между одной цифрой Char и соответствующим Int. digitToInt завершается неуспешно, если ее аргумент не удовлетворяет условию isHexDigit, но она распознает шестнадцатиричные цифры как в верхнем, так и в нижнем регистрах (т.е. '0' .. '9', 'a'.. 'f', 'A' .. 'F'). intToDigit завершается неуспешно, если ее аргумент не находится в диапазоне 0.. 15; она генерирует шестнадцатиричные цифры в нижнем регистре.

Функция isSpace распознает пробельные символы только в диапазоне Latin 1.

Функция showLitChar преобразует символ в строку, используя только печатаемые символы и соглашения исходного языка Haskell об эскейп-символах. Функция lexLitChar делает обратное, возвращая последовательность символов, которые кодируют символ. Функция readLitChar делает то же самое, но кроме того осуществляет преобразование к символу, который это кодирует. Например:

  showLitChar '\n' s       =  "\\n" ++ s
  lexLitChar  "\\nЗдравствуйте"   =  [("\\n", "Здравствуйте")]
  readLitChar "\\nЗдравствуйте"   =  [('\n', "Здравствуйте")]

Функция toUpper преобразовывает букву в соответствующую заглавную букву, оставляя все остальные символы без изменений. Любая буква Unicode, которая имеет эквивалент в верхнем регистре, подвергается преобразованию. Аналогично, toLower преобразовывает букву в соответствующую строчную букву, оставляя все остальные символы без изменений.

Функции ord и chr являются функциями fromEnum и toEnum, ограниченными типом Char.

19.1  Библиотека Char


module Char ( 
    isAscii, isLatin1, isControl, isPrint, isSpace, isUpper, isLower,
    isAlpha, isDigit, isOctDigit, isHexDigit, isAlphaNum,
    digitToInt, intToDigit,
    toUpper, toLower,
    ord, chr,
    readLitChar, showLitChar, lexLitChar,

        -- ...и то, что экспортирует Prelude
    Char, String
    ) where

import Array         -- Используется для таблицы имен символов.
import Numeric (readDec, readOct, lexDigits, readHex)
import UnicodePrims  -- Исходный код примитивных функций Unicode.

-- Операции проверки символов
isAscii, isLatin1, isControl, isPrint, isSpace, isUpper, isLower,
 isAlpha, isDigit, isOctDigit, isHexDigit, isAlphaNum :: Char -> Bool

isAscii c                =  c < '\x80'

isLatin1 c               =  c <= '\xff'

isControl c              =  c < ' ' || c >= '\DEL' && c <= '\x9f'

isPrint                  =  primUnicodeIsPrint

isSpace c                =  c `elem` " \t\n\r\f\v\xA0"
        -- Распознаются только пробельные символы Latin-1

isUpper                  =  primUnicodeIsUpper  -- 'A'..'Z'

isLower                  =  primUnicodeIsLower  -- 'a'..'z'

isAlpha c                =  isUpper c || isLower c

isDigit c                =  c >= '0' && c <= '9'

isOctDigit c             =  c >= '0' && c <= '7'

isHexDigit c             =  isDigit c || c >= 'A' && c <= 'F' ||
                                         c >= 'a' && c <= 'f'

isAlphaNum               =  primUnicodeIsAlphaNum


-- Операции преобразования цифр
digitToInt :: Char -> Int
digitToInt c
  | isDigit c            =  fromEnum c - fromEnum '0'
  | c >= 'a' && c <= 'f' =  fromEnum c - fromEnum 'a' + 10
  | c >= 'A' && c <= 'F' =  fromEnum c - fromEnum 'A' + 10
  | otherwise            =  error "Char.digitToInt: не является цифрой"

intToDigit :: Int -> Char
intToDigit i
  | i >= 0  && i <=  9   =  toEnum (fromEnum '0' + i)
  | i >= 10 && i <= 15   =  toEnum (fromEnum 'a' + i - 10)
  | otherwise            =  error "Char.intToDigit: не является цифрой"


-- Операции изменения регистра букв
toUpper :: Char -> Char
toUpper =  primUnicodeToUpper
        
toLower :: Char -> Char
toLower =  primUnicodeToLower

-- Функции кодирования символов
ord  :: Char -> Int
ord  =  fromEnum
     
chr  :: Int  -> Char
chr  =  toEnum

-- Функции над текстом
readLitChar          :: ReadS Char
readLitChar ('\\':s) =  readEsc s
readLitChar (c:s)    =  [(c,s)]

readEsc          :: ReadS Char
readEsc ('a':s)  = [('\a',s)]
readEsc ('b':s)  = [('\b',s)]
readEsc ('f':s)  = [('\f',s)]
readEsc ('n':s)  = [('\n',s)]
readEsc ('r':s)  = [('\r',s)]
readEsc ('t':s)  = [('\t',s)]
readEsc ('v':s)  = [('\v',s)]
readEsc ('\\':s) = [('\\',s)]
readEsc ('"':s)  = [('"',s)]
readEsc ('\'':s) = [('\'',s)]
readEsc ('^':c:s) | c >= '@' && c <= '_'
                 = [(chr (ord c - ord '@'), s)]
readEsc s@(d:_) | isDigit d
                 = [(chr n, t) | (n,t) <- readDec s]
readEsc ('o':s)  = [(chr n, t) | (n,t) <- readOct s]
readEsc ('x':s)  = [(chr n, t) | (n,t) <- readHex s]
readEsc s@(c:_) | isUpper c
                 = let table = ('\DEL', "DEL") : assocs asciiTab
                   in case [(c,s') | (c, mne) <- table,
                                     ([],s') <- [match mne s]]
                      of (pr:_) -> [pr]
                         []     -> []
readEsc _        = []

match                         :: (Eq a) => [a] -> [a] -> ([a],[a])
match (x:xs) (y:ys) | x == y  =  match xs ys
match xs     ys               =  (xs,ys)

showLitChar               :: Char -> ShowS
showLitChar c | c > '\DEL' =  showChar '\\' . 
                              protectEsc isDigit (shows (ord c))
showLitChar '\DEL'         =  showString "\\DEL"
showLitChar '\\'           =  showString "\\\\"
showLitChar c | c >= ' '   =  showChar c
showLitChar '\a'           =  showString "\\a"
showLitChar '\b'           =  showString "\\b"
showLitChar '\f'           =  showString "\\f"
showLitChar '\n'           =  showString "\\n"
showLitChar '\r'           =  showString "\\r"
showLitChar '\t'           =  showString "\\t"
showLitChar '\v'           =  showString "\\v"
showLitChar '\SO'          =  protectEsc (== 'H') (showString "\\SO")
showLitChar c              =  showString ('\\' : asciiTab!c)

protectEsc p f             = f . cont
                             where cont s@(c:_) | p c = "\\&" ++ s
                                   cont s             = s
asciiTab = listArray ('\NUL', ' ')
           ["NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
            "BS",  "HT",  "LF",  "VT",  "FF",  "CR",  "SO",  "SI", 
            "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
            "CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US", 
            "SP"] 

lexLitChar          :: ReadS String
lexLitChar ('\\':s) =  map (prefix '\\') (lexEsc s)
        where
          lexEsc (c:s)     | c `elem` "abfnrtv\\\"'" = [([c],s)]
          lexEsc ('^':c:s) | c >= '@' && c <= '_'    = [(['^',c],s)]

          -- Числовые эскейп-символы
          lexEsc ('o':s)               = [prefix 'o' (span isOctDigit s)]
          lexEsc ('x':s)               = [prefix 'x' (span isHexDigit s)]
          lexEsc s@(d:_)   | isDigit d = [span isDigit s]

          -- Очень грубое приближение к \XYZ.
          lexEsc s@(c:_)   | isUpper c = [span isCharName s]
          lexEsc _                     = []

          isCharName c   = isUpper c || isDigit c
          prefix c (t,s) = (c:t, s)

lexLitChar (c:s)    =  [([c],s)]
lexLitChar ""       =  []



Описание Haskell 98
наверх | назад | вперед | содержание | предметный указатель функций
Декабрь 2002