Конвертировать UTF-16 в UTF-8 и удалить BOM? - PullRequest
20 голосов
/ 12 января 2012

У нас есть сотрудник по вводу данных, который закодировал UTF-16 в Windows и хотел бы иметь utf-8 и удалить спецификацию.Преобразование utf-8 работает, но спецификация все еще там.Как бы я это убрал?Вот что у меня сейчас:

batch_3={'src':'/Users/jt/src','dest':'/Users/jt/dest/'}
batches=[batch_3]

for b in batches:
  s_files=os.listdir(b['src'])
  for file_name in s_files:
    ff_name = os.path.join(b['src'], file_name)  
    if (os.path.isfile(ff_name) and ff_name.endswith('.json')):
      print ff_name
      target_file_name=os.path.join(b['dest'], file_name)
      BLOCKSIZE = 1048576
      with codecs.open(ff_name, "r", "utf-16-le") as source_file:
        with codecs.open(target_file_name, "w+", "utf-8") as target_file:
          while True:
            contents = source_file.read(BLOCKSIZE)
            if not contents:
              break
            target_file.write(contents)

Если я hexdump -CI вижу:

Wed Jan 11$ hexdump -C svy-m-317.json 
00000000  ef bb bf 7b 0d 0a 20 20  20 20 22 6e 61 6d 65 22  |...{..    "name"|
00000010  3a 22 53 61 76 6f 72 79  20 4d 61 6c 69 62 75 2d  |:"Savory Malibu-|

в полученном файлеКак удалить спецификацию?

thx

Ответы [ 2 ]

36 голосов
/ 12 января 2012

Это разница между UTF-16LE и UTF-16

  • UTF-16LE с прямым порядком байтов без спецификация
  • UTF-16 большаяили little endian с спецификацией

Таким образом, когда вы используете UTF-16LE, спецификация является лишь частью текста.Вместо этого используйте UTF-16, чтобы спецификация автоматически удалялась.Причина существования UTF-16LE и UTF-16BE заключается в том, что люди могут носить с собой «правильно закодированный» текст без спецификаций, что к вам не относится.

Обратите внимание, что происходит, когда вы кодируете с использованием одного кодирования и декодируете сдругой.(UTF-16 автоматически обнаруживает UTF-16LE иногда, не всегда.)

>>> u'Hello, world'.encode('UTF-16LE')
'H\x00e\x00l\x00l\x00o\x00,\x00 \x00w\x00o\x00r\x00l\x00d\x00'
>>> u'Hello, world'.encode('UTF-16')
'\xff\xfeH\x00e\x00l\x00l\x00o\x00,\x00 \x00w\x00o\x00r\x00l\x00d\x00'
 ^^^^^^^^ (BOM)

>>> u'Hello, world'.encode('UTF-16LE').decode('UTF-16')
u'Hello, world'
>>> u'Hello, world'.encode('UTF-16').decode('UTF-16LE')
u'\ufeffHello, world'
    ^^^^ (BOM)

Или вы можете сделать это в оболочке:

for x in * ; do iconv -f UTF-16 -t UTF-8 <"$x" | dos2unix >"$x.tmp" && mv "$x.tmp" "$x"; done
24 голосов
/ 12 января 2012

Просто используйте str.decode и str.encode:

with open(ff_name, 'rb') as source_file:
  with open(target_file_name, 'w+b') as dest_file:
    contents = source_file.read()
    dest_file.write(contents.decode('utf-16').encode('utf-8'))

str.decode избавит вас от спецификации (и выведет порядок байтов)).

...