Software Tools in Haskell: charfullwidth

replace chars with fullwidth equivalents

Posted on 2016-02-17 by nbloomf
Tags: software-tools-in-haskell, literate-haskell

This page is part of a series on Software Tools in Haskell.

This post is literate Haskell; you can load the source into GHCi and play along.


As usual, we start with some imports.

-- sth-charfullwidth: replace characters with fullwidth equivalents
module Main where

import System.Exit (exitSuccess)

Replacing “normal” characters with fullwidth forms is much simpler. We reuse the structure of copy --char, with a filter to map characters.

main :: IO ()
main = do
  charFilter (map toFullwidth)
  exitSuccess

And the map:

toFullwidth :: Char -> Char
toFullwidth = applyListMap full
  where
    full =
      [ ('!','!'), ('"','"'),  ('#','#'), ('$','$'), ('%','%')
      , ('&','&'), ('\'','''), ('(','('), (')',')'), ('*','*')
      , ('+','+'), (',',','),  ('-','-'), ('.','.'), ('/','/')
      , ('0','0'), ('1','1'),  ('2','2'), ('3','3'), ('4','4')
      , ('5','5'), ('6','6'),  ('7','7'), ('8','8'), ('9','9')
      , (':',':'), (';',';'),  ('<','<'), ('=','='), ('>','>')
      , ('?','?'), ('@','@'),  ('A','A'), ('B','B'), ('C','C')
      , ('D','D'), ('E','E'),  ('F','F'), ('G','G'), ('H','H')
      , ('I','I'), ('J','J'),  ('K','K'), ('L','L'), ('M','M')
      , ('N','N'), ('O','O'),  ('P','P'), ('Q','Q'), ('R','R')
      , ('S','S'), ('T','T'),  ('U','U'), ('V','V'), ('W','W')
      , ('X','X'), ('Y','Y'),  ('Z','Z'), ('[','['), ('\\','\')
      , (']',']'), ('^','^'),  ('_','_'), ('`','`'), ('a','a')
      , ('b','b'), ('c','c'),  ('d','d'), ('e','e'), ('f','f')
      , ('g','g'), ('h','h'),  ('i','i'), ('j','j'), ('k','k')
      , ('l','l'), ('m','m'),  ('n','n'), ('o','o'), ('p','p')
      , ('q','q'), ('r','r'),  ('s','s'), ('t','t'), ('u','u')
      , ('v','v'), ('w','w'),  ('x','x'), ('y','y'), ('z','z')
      , ('{','{'), ('|','|'),  ('}','}'), ('~','~'), (' ',' ')
      ]

This probably looks terrible in your browser because unicode coverage. The applyListMap function treats a list of pairs like a mapping.

applyListMap :: (Eq a) => [(a,a)] -> a -> a
applyListMap zs x = case lookup x zs of
  Nothing -> x
  Just y  -> y

-- apply a map to stdin
charFilter :: (String -> String) -> IO ()
charFilter f = do
  xs <- getContents
  putStr $ f xs