控制台输出bytestrings - 删除下一行的第一个字符

时间:2016-02-28 22:38:45

标签: haskell unicode bytestring

回答haskell-convert-unicode-sequence-to-utf-8我遇到了ByteString.putStrLn

的一些奇怪行为
{-# LANGUAGE OverloadedStrings #-}

module Main where

import           Data.Text (Text)
import           Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as B


inputB, inputB' :: ByteString
inputB = "ДЕЖЗИЙКЛМНОПРСТУФ"
inputB' = "test"


main :: IO ()
main = do putStr "B.putStrLn inputB: "; B.putStrLn inputB
          putStr "print inputB: "; print inputB
          putStr "B.putStrLn inputB': "; B.putStrLn inputB'
          putStr "print inputB': "; print inputB'

产生

B.putStrLn inputB:
rint inputB: "\DC4\NAK\SYN\ETB\CAN\EM\SUB\ESC\FS\GS\RS\US !\"#$"
B.putStrLn inputB': test
print inputB': "test"

我在这里不明白的是 - 为什么第一行输出行缺少第二行打印的 p 缺失。

我的猜测是,这与导致输入错误的俄语字母有关。因为简单的“测试”案例才有效。

修改

  • 平台:Linux Mint 17.3
  • 文件编码:UTF-8
  • terminal:gnome-terminal / tmux / zsh
  • ghc:7.10.3
  • stack:1.0.4

xxd输出

> stack exec -- unicode | xxd
00000000: 422e 7075 7453 7472 4c6e 2069 6e70 7574  B.putStrLn input
00000010: 423a 2014 1516 1718 191a 1b1c 1d1e 1f20  B: ............
00000020: 2122 2324 0a70 7269 6e74 2069 6e70 7574  !"#$.print input
00000030: 423a 2022 5c44 4334 5c4e 414b 5c53 594e  B: "\DC4\NAK\SYN
00000040: 5c45 5442 5c43 414e 5c45 4d5c 5355 425c  \ETB\CAN\EM\SUB\
00000050: 4553 435c 4653 5c47 535c 5253 5c55 5320  ESC\FS\GS\RS\US
00000060: 215c 2223 2422 0a42 2e70 7574 5374 724c  !\"#$".B.putStrL
00000070: 6e20 696e 7075 7442 273a 2074 6573 740a  n inputB': test.
00000080: 7072 696e 7420 696e 7075 7442 273a 2022  print inputB': "
00000090: 7465 7374 220a                           test".

文库

> stack exec -- ghc-pkg list
/opt/ghc/7.10.3/lib/ghc-7.10.3/package.conf.d
   Cabal-1.22.5.0
   array-0.5.1.0
   base-4.8.2.0
   bin-package-db-0.0.0.0
   binary-0.7.5.0
   bytestring-0.10.6.0
   containers-0.5.6.2
   deepseq-1.4.1.1
   directory-1.2.2.0
   filepath-1.4.0.0
   ghc-7.10.3
   ghc-prim-0.4.0.0
   haskeline-0.7.2.1
   hoopl-3.10.0.2
   hpc-0.6.0.2
   integer-gmp-1.0.0.0
   pretty-1.1.2.0
   process-1.2.3.0
   rts-1.0
   template-haskell-2.10.0.0
   terminfo-0.4.0.1
   time-1.5.0.1
   transformers-0.4.2.0
   unix-2.7.1.0
   xhtml-3000.2.1
/home/epsilonhalbe/.stack/snapshots/x86_64-linux/lts-5.5/7.10.3/pkgdb
   text-1.2.2.0
/home/epsilonhalbe/programming/unicode/.stack-work/install/x86_64-linux/lts-5.5/7.10.3/pkgdb

和语言环境

> locale
LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=de_AT.UTF-8
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=de_AT.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=de_AT.UTF-8
LC_NAME=de_AT.UTF-8
LC_ADDRESS=de_AT.UTF-8
LC_TELEPHONE=de_AT.UTF-8
LC_MEASUREMENT=de_AT.UTF-8
LC_IDENTIFICATION=de_AT.UTF-8
LC_ALL=

2 个答案:

答案 0 :(得分:1)

这不是终端问题,而是在转换为ByteString的早期问题发生。请记住,因为您使用了OverloadedStrings

inputB = "ДЕЖЗИЙКЛМНОПРСТУФ"

的简写
inputB = fromString "ДЕЖЗИЙКЛМНОПРСТУФ"::ByteString

使用UTF8不会转换为字节字符串。

相反,如果您希望bytestring包含utf8编码的字符,请使用

import qualified Data.ByteString.UTF8 as BU

inputB = BU.fromString "ДЕЖЗИЙКЛМНОПРСТУФ"

然后这将起作用

B.putStrLn inputB

为什么第二行的“p”缺失?

我不会详细说明(因为我不知道它们),但行为是预期的....因为你的终端期待UTF8,俄语字符串不是UTF8。

UTF8使用可变长度字节字符编码....根据char中的第一个字节,它可能会有更多。很明显,俄语字符串中的最后一个字节开始需要更多字节的UTF8编码,并且“p”被读入该字符串。你的终端似乎只是忽略它无法打印的字符(我的打印垃圾),所以俄罗斯字符串和下一个字符都丢失了。

你会注意到“p”在xxd输出中....终端只是认为它是未知字符的一部分而不是打印它。

答案 1 :(得分:1)

引自Data.ByteString.Char8的文件 (强调我的)

  

使用Char操作处理ByteStrings。 所有的Chars都会   截断为8位。可以预期这些函数将运行   与Data.ByteString中的Word8等效速度相同。

     

更具体地说,这些字节字符串被​​认为是在子集中   代码点0-255涵盖的Unicode。这包括Unicode Basic Latin,   Latin-1 Supplement和C0 + C1 Controls。

Cyrillic未在代码点0x00-0xFF中分配,因此可以预期编码问题。

除非您处理纯ASCII,否则我建议反对 Data.ByteString.Char8。即使拉丁-1编码的文本可能在某些环境中起作用,拉丁-1编码也会过时并且应该死掉。

要处理常规字符串,请改用Data.Text。转换功能从ByteString s到Text,反之亦然,are provided。当然,这些功能必须依赖于某些编码。