必要なので半角カナ文字を含む文字列を全角文字列に変換する関数を書きました。
半角文字のUCS4コードはSJISと同じ順序で並んでいますので、半角文字をそのまま配列の添え字に使って全角文字を取得しています。
まず、listArrayで半角カナ文字コードと同じ順番の全角文字リストから配列を作ります。
isHan関数で半角文字かどうか判断し、半角文字のときは zenArray ! c で全角文字に変換しています。
import Data.Array import Data.Char import Numeric import Codec.Binary.UTF8.String -- ASCIIコードの空いている部分に割り当てたときは 0xA1-0xDF。 -- UCS4 では 0xFF61-0xFF9F -- hanKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚" zenArray :: Array Char Char zenArray = listArray (chr 0xff61,chr 0xff9f) zenKana where zenKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜" hanSTRToZen :: String -> String hanSTRToZen s = foldr ifHan2Zen "" s where ifHan2Zen :: Char -> String -> String ifHan2Zen c acc = if isHan c then (zenArray ! c):acc else c:acc isHan :: Char -> Bool isHan c = 0xff61 <= n && n <= 0xff9f where n = ord c main ::IO() main = do putStrLn $ encodeString $ hanSTRToZen "半角文字列「アイウエオカキクケコサシスセソタチツ」を変換。" -- > 半角文字列「アイウエオカキクケコサシスセソタチツ」を変換。
Data.Map を使って全角カナ文字を半角文字に変換。
module Main where import qualified Data.Map as M import Codec.Binary.UTF8.String hanKana :: String hanKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚" zenKana :: String zenKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜" zenSTRToHan :: String -> String zenSTRToHan s = foldr ifZen2Han "" s where ifZen2Han :: Char -> String -> String ifZen2Han c acc = case M.lookup c kanaMap of Just han -> han:acc Nothing -> c:acc kanaMap :: M.Map Char Char kanaMap = M.fromList $ zip zenKana hanKana main ::IO() main = do putStrLn $ encodeString $ zenSTRToHan "全角文字列「。「」、・ヲァィゥェォッーアイウ」を半角に変換。" -- > 全角文字列「。「」、・ヲァィゥェォッーアイウ」を半角に変換。
- "。「」、・" はカナでないので覗くべきです。
- 濁点、半濁点の文字は、全角から半角に変換するときは一文字から二文字に、その逆のときは二文字から一文字に変換する必要があります。
半角カナから全角カナへの変換(濁点、半濁点に対応)
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE CPP #-} import Foreign.Ptr import Foreign.C.String import Foreign.C.Types import Foreign.Marshal.Alloc import Data.Array #define CP_ACP 0 utf16ToShiftJis :: String -> IO String utf16ToShiftJis string = do cstring <- withCWString string bstrToCString str <- peekCString cstring free cstring return str where bstrToCString :: Ptr CWchar -> IO CString bstrToCString bstr = do out_size <- cWideCharToMultiByte CP_ACP 0 bstr (-1) nullPtr 0 nullPtr nullPtr cstring <- mallocBytes ((fromIntegral out_size) + 1):: IO (Ptr CChar) _ <- cWideCharToMultiByte CP_ACP 0 bstr (-1) cstring out_size nullPtr nullPtr return cstring -- http://msdn.microsoft.com/ja-jp/library/cc448089.aspx foreign import stdcall "windows.h WideCharToMultiByte" cWideCharToMultiByte :: CUInt -> -- UINT CodePage, // コードページ CULong -> -- DWORD dwFlags, // 処理速度とマッピング方法を決定するフラグ Ptr CWchar -> -- LPCWSTR lpWideCharStr, // ワイド文字列のアドレス CInt -> -- int cchWideChar, // ワイド文字列の文字数 CString -> -- LPSTR lpMultiByteStr, // 新しい文字列を受け取るバッファのアドレス CInt -> -- int cchMultiByte, // 新しい文字列を受け取るバッファのサイズ CString -> -- LPCSTR lpDefaultChar, // マップできない文字の既定値のアドレス Ptr Int -> -- LPBOOL lpUsedDefaultChar //既定の文字を使ったときにセットするフラグのアドレス IO CInt -- ASCIIコードの空いている部分に割り当てたときは 0xA1-0xDF。 -- UCS4 では 0xFF61-0xFF9F -- hanKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚" hanSTRToZen :: String -> String hanSTRToZen s = hanSTRToZen' s "" hanSTRToZen' :: String -> String -> String hanSTRToZen' "" acc = reverse acc hanSTRToZen' (x:xs) acc = if isHan x then case xs of "" -> hanSTRToZen' xs ((zenArray ! x):acc) ('゙':cs) -> if isDakuten x then hanSTRToZen' cs ((dakuArray ! x):acc) else hanSTRToZen' cs ('゛':(zenArray ! x):acc) ('゚':cs) -> if isHanDaku x then hanSTRToZen' cs ((handakuAry ! x):acc) else hanSTRToZen' cs ('゜':(zenArray ! x):acc) _ -> hanSTRToZen' xs ((zenArray ! x):acc) else hanSTRToZen' xs (x:acc) where isHan :: Char -> Bool isHan c = '。' <= c && c <= '゚' isDakuten :: Char -> Bool isDakuten c = ('カ' <= c && c <= 'ト') || ('ハ' <= c && c <= 'ホ') isHanDaku :: Char -> Bool isHanDaku c = 'ハ' <= c && c <= 'ホ' zenArray :: Array Char Char zenArray = listArray ('。','゚') zenKana where zenKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜" dakuArray :: Array Char Char dakuArray = listArray ('カ','ホ') dakuten where dakuten = "ガギグゲゴザジズゼゾダデヅデドナニヌネノバビブベボ" handakuAry :: Array Char Char handakuAry = listArray ('ハ','ホ') handaku where handaku = "パピプペポ" main ::IO() main = do putStrLn =<< utf16ToShiftJis "文字列" putStrLn =<< utf16ToShiftJis (hanSTRToZen "半角文字列「ガギグゲゴザジズゼゾダヂヅデド」を変換。") putStrLn =<< utf16ToShiftJis (hanSTRToZen "半角文字列「バビブベボマミムメモ」を変換。") putStrLn =<< utf16ToShiftJis (hanSTRToZen "半角文字列「パピプペポマミムメモ」を変換。") putStrLn =<< utf16ToShiftJis (hanSTRToZen "濁点、半濁点の誤用「ア゙イ゙ウエオカキクケコサシ゚ス゚セソタチツ」を変換。") -- $ ghc --make -Wall han2zen.hs -- $ ./han2zen -- 文字列 -- 半角文字列「ガギグゲゴザジズゼゾダデヅデド」を変換。 -- 半角文字列「バビブベボマミムメモ」を変換。 -- 半角文字列「パピプペポマミムメモ」を変換。 -- 濁点、半濁点の誤用「ア゛イ゛ウエオカキクケコサシ゜ス゜セソタチツ」を変換。
参考
全角カナから半角カナへの変換(濁点、半濁点に対応)
module Main where import qualified Data.Map as M import Codec.Binary.UTF8.String hanKana :: String hanKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚" zenKana :: String zenKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜" dakuMap :: M.Map Char (Char,Char) dakuMap = M.fromList $ zip "ガギグゲゴザジズゼゾダデヅデドバビブベボパピプペポ" ((zip "カキクケコサシスセソタチツテトハヒフヘホ" (repeat '゙')) ++ (zip "ハヒフヘホ" (repeat '゚'))) zenSTRToHan :: String -> String zenSTRToHan s = foldr ifZen2Han "" s where ifZen2Han :: Char -> String -> String ifZen2Han c acc = case M.lookup c kanaMap of Just han -> han:acc Nothing -> case M.lookup c dakuMap of Just (c1,c2) -> (c1:c2:acc) Nothing -> c:acc kanaMap :: M.Map Char Char kanaMap = M.fromList $ zip zenKana hanKana main ::IO() main = do putStrLn $ encodeString $ zenSTRToHan "全角文字列「。「」、・ヲァィゥェォッーアイウ」を半角に変換。" putStrLn $ encodeString $ zenSTRToHan "全角文字列ガギグゲゴザジズゼゾダデヅデドバビブベボパピプペポに変換。" -- 全角文字列「。「」、・ヲァィゥェォッーアイウ」を半角に変換。 -- 全角文字列ガギグゲゴザジズゼゾダデヅデドバビブベボパピプペポに変換。