Haskell #18.3 Module

 

Data.Char

lego char

Module Data.Char thực hiện những nhiệm vụ mà tên gọi của nó gợi ra. Nó xuất khẩu những hàm thao tác với kí tự. Module này cũng có ích đối với việc lọc và ánh xạ trên các chuỗi vì chuỗi chỉ là danh sách các kí tự.

Data.Char xuất khẩu một loạt những vị từ thao tác với kí tự; nghĩa là những hàm nhận vào một kí tự rồi cho ta biết rằng liệu một giả thiết nào về kí tự này là đúng hay sai. Sau đây là các vị từ:

isControl kiểm tra xem một kí tự có phải là kí tự điều khiển hay không.

isSpace kiểm tra xem một kí tự có phải là kí tự trắng hay không; các kí tự trắng gồm có dấu cách, tab, xuống dòng, v.v.

isLower kiểm tra xem một kí tự có phải là chữ thường không.

isUpper kiểm tra xem một kí tự có phải là chữ in không.

isAlpha kiểm tra xem một kí tự có phải là chữ cái không.

isAlphaNum kiểm tra xem một kí tự có phải là chữ cái hoặc chữ số không.

isPrint kiểm tra xem một kí tự có in được hay không. Những kí tự như kí tự điều khiển chẳng hạn, thì không in được.

isDigit kiểm tra xem một kí tự có phải là chữ số không.

isOctDigit kiểm tra xem một kí tự có phải là chữ số trong hệ bát phân không.

isHexDigit kiểm tra xem một kí tự có phải là chữ số trong hệ thập lục phân không.

isLetter kiểm tra xem một kí tự có phải là chữ cái không. [Hai hàm isLetter và isAlpha tương đương với nhau.]

isMark kiểm tra kí tự dấu Unicode; những kí tự dấu này kết hợp với kí tự liền trước nó để tạo thành các chữ có dấu. Nếu bạn nói tiếng Pháp, hãy dùng hàm này.

isNumber kiểm tra xem một kí tự có phải là chữ số không.

isPunctuation kiểm tra xem một kí tự có phải là dấu câu không.

isSymbol kiểm tra xem một kí tự có phải là dấu kí hiệu toán hoặc kí hiệu tiền tệ không.

isSeparator kiểm tra các dấu trống và dấu ngăn cách Unicode.

isAscii kiểm tra xem một kí tự có rơi vào nhóm 128 kí tự đầu tiên trong bảng mã Unicode không.

isLatin1 kiểm tra xem một kí tự có rơi vào nhóm 256 kí tự đầu tiên trong bảng mã Unicode không.

isAsciiUpper kiểm tra xem một kí tự có phải là ASCII và viết in không.

isAsciiLower kiểm tra xem một kí tự có phải là ASCII và viết thường không.

Tất cả những vị từ này đều có dấu ấn kiểu là Char -> Bool. Trong đa số các trường hợp bạn sẽ dùng đặc điểm này để lọc ra chuỗi hoặc những thứ như vậy. Chẳng hạn, giả sử ta viết một chương trình nhận vào tên người dùng mà tên gọi này chỉ chứa những chữ cái. Ta có thể dùng hàm all trong Data.List kết hợp với vị từ Data.Char để quyết định xem tên được nhập vào đó có hợp lệ không.

ghci> all isAlphaNum "bobby283"
True
ghci> all isAlphaNum "eddy the fish!"
False

Hay! Trong trường hợp bạn không nhớ, all nhận vào một vị từ cùng một danh sách rồi trả lại True chỉ khi vị từ đó thỏa mãn tất cả các phần tử trong danh sách.

Ta cũng có thể dùng isSpace để mô phỏng hàm words trong Data.List.

ghci> words "hey guys its me"
["hey","guys","its","me"]
ghci> groupBy ((==) `on` isSpace) "hey guys its me"
["hey"," ","guys"," ","its"," ","me"]
ghci>

Hừm, được rồi, nó hoạt động kiểu như words song bỏ lại cho ta những phần tử chỉ chứa những dấu cách. Hừm, ta sẽ làm gì đây? Tôi biết rồi, hãy lọc đi những thứ rác đó.

ghci> filter (not . any isSpace) . groupBy ((==) `on` isSpace) $ "hey guys its me"
["hey","guys","its","me"]

A ha!

Lớp Data.Char cũng xuất khẩu một kiểu dữ liệu giống như Ordering. Kiểu Ordering có thể nhận giá trị LTEQ hoặc GT. Đó là một dạng liệt kê. Nó mô tả một vài kết quả có thể xảy ra khi so sánh hai phần tử. Kiểu GeneralCategory cũng là một dạng liệt kê. Nó trình bày một số thể loại mà một kí tự có thể rơi vào. Hàm cơ bản để lấy thể loại tổng quát của một kí tự là generalCategory. Nó có kiểu generalCategory :: Char -> GeneralCategory. Có khoảng 31 thể loại, vì vậy chúng tôi sẽ không kể hết ra ở đây, nhưng ta hãy thử dùng hàm này xem.

ghci> generalCategory ' '
Space
ghci> generalCategory 'A'
UppercaseLetter
ghci> generalCategory 'a'
LowercaseLetter
ghci> generalCategory '.'
OtherPunctuation
ghci> generalCategory '9'
DecimalNumber
ghci> map generalCategory " \t\nA9?|"
[Space,Control,Control,UppercaseLetter,DecimalNumber,OtherPunctuation,MathSymbol]

Vì kiểu GeneralCategory là một phần của lớp Eq, ta cũng có thể kiểm tra những thứ như generalCategory c == Space.

toUpper chuyển một kí tự thành chữ viết in. Các dấu cách, chữ số, v.v. giữ nguyên không đổi.

toLower chuyển một kí tự thành chữ viết thường.

toTitle chuyển một kí tự thành chữ tiêu đề. Tuyệt đại đa số kí tự thfi chữ tiêu đề cũng như chữu viết in.

digitToInt chuyển một kí tự thành kiểu Int. Muốn chuyển đổi được, kí tự phải nằm trong khoảng '0'..'9''a'..'f' hoặc 'A'..'F'.

ghci> map digitToInt "34538"
[3,4,5,3,8]
ghci> map digitToInt "FF85AB"
[15,15,8,5,10,11]

intToDigit là hàm ngược của digitToInt. Nó nhận vào một Int trong khoảng từ 0..15 rồi chuyển sang một chữ cái viết thường.

ghci> intToDigit 15
'f'
ghci> intToDigit 5
'5'

Các hàm ord và chr chuyển đổi kí tự thành số tương ứng và ngược lại:

ghci> ord 'a'
97
ghci> chr 97
'a'
ghci> map ord "abcdefgh"
[97,98,99,100,101,102,103,104]

Hiệu số giữa hai giá trị ord của hai kí tự sẽ bằng khoảng cách giữa hai kí tự đó trong bảng mã Unicode.

Mật mã Caesar là một phương pháp thô sơ để mã hóa thông điệp chứa nhiều kí tự bằng cách chuyển từng kí tự đi một số vị trí nhất định trong bảng chữ cái. Ta có thể dễ dàng tạo ra một dạng mật mã Caesar, chỉ khác là không bị giới hạn ở những kí tự trong bảng chữ cái.

encode :: Int -> String -> String
encode shift msg =
    let ords = map ord msg
        shifted = map (+ shift) ords
    in  map chr shifted

Ở đây, đầu tiên là ta chuyển chuỗi thành một danh sách các số. Sau đó ta đem cộng khoảng dịch chuyển vào từng số trước khi chuyển ngược danh sách số về những kí tự. Nếu là người chuyên dùng hàm hợp thì bạn có thể viết phần thân của hàm này như sau:map (chr . (+ shift) . ord) msg. Ta hãy thử mã hóa một vài thông điệp.

ghci> encode 3 "Heeeeey"
"Khhhhh|"
ghci> encode 4 "Heeeeey"
"Liiiii}"
ghci> encode 1 "abcd"
"bcde"
ghci> encode 5 "Marry Christmas! Ho ho ho!"
"Rfww~%Hmwnxyrfx&%Mt%mt%mt&"

Việc mã hóa như vậy là ổn. Việc giải mã về cơ bản là dịch chuyển ngược về một số vị trí như ban đầu đã dịch chuyển đi.

decode :: Int -> String -> String
decode shift msg = encode (negate shift) msg
ghci> encode 3 "Im a little teapot"
"Lp#d#olwwoh#whdsrw"
ghci> decode 3 "Lp#d#olwwoh#whdsrw"
"Im a little teapot"
ghci> decode 5 . encode 5 $ "This is a sentence"
"This is a sentence"