Скрипт для преобразования символов Юникода вформат в их эквиваленты ASCII - PullRequest
2 голосов
/ 03 апреля 2011

Я делаю некоторые изменения в файлах локалей Linux /usr/share/i18n/locales (например, pt_BR), чтобы изменить формат даты, времени, чисел и т. Д., Но по умолчанию символы Unicode представлены в виде строк в формате <U9999>, поэтому текст очень трудно читать.

Вот фрагмент этого кода:

LC_TIME
abday   "<U0044><U006F><U006D>";"<U0053><U0065><U0067>";/
    "<U0054><U0065><U0072>";"<U0051><U0075><U0061>";/
    "<U0051><U0075><U0069>";"<U0053><U0065><U0078>";/
    "<U0053><U00E1><U0062>"

Итак, как сделать простой скрипт (может быть bash, python, pearl и т. Д.) Для преобразования этого текста, заменяя коды <Uxxxx> на их эквиваленты ASCII? (да, все они имеют показатели ASCI ниже 255, большинство даже ниже 127)

Если получено несколько ответов, я приму наиболее элегантный и / или более подробный объясненный (например, параметры и флаги, используемые в командах)

Например, приведенный выше текст будет преобразован в:

LC_TIME
abday   "Dom";"Seg";/
    "Ter";"Qua";/
    "Qui";"Sex";/
    "Sáb"

Бонусные баллы за другой скрипт, который может сделать обратное: преобразовать все символы данной строки в <Uxxx> формат.

Спасибо!

Ответы [ 2 ]

2 голосов
/ 03 апреля 2011

Использование полей

#!/bin/bash

awk -F'<U0+|>' '{
    for(i=1;i<=NF;i++)
        if($i ~ "^[0-9A-F]+$")
            $i=sprintf("%c", strtonum("0x"$i))
}1' OFS="" /path/to/infile

Объяснение

  1. -F'<U0+|>': это магия, которая делает этот сценарий таким коротким. Мы говорим awk, что разделитель полей либо <U0+, либо простой >. Преимущество этого состоит в том, что awk автоматически удалит эти символы для нас, поэтому нам не нужно делать это вручную с gsub(), когда придет время для преобразования strtonum ().

  2. for(i=1;i<=NF;i++): итерация по каждому полю

  3. if($i ~ "^[0-9A-F]+$"): проверить, состоит ли текущее поле только из шестнадцатеричных цифр. Помните, что из-за # 1 выше что-то вроде <U006F> будет рассматриваться как 6F в этой точке
  4. $i=sprintf("%c", strtonum("0x"$i)): заменить шестнадцатеричную цифру на соответствующее значение ascii. Мы должны поставить перед полем $i значение "0x", чтобы awk знал его шестнадцатеричное значение
  5. }1: ярлык для обязательного print или всегда печатать каждую строку
  6. OFS="": установить разделитель поля вывода на нулевую строку. Если мы этого не сделаем, мы получим пробелы в выводе везде, где было <U0+ или >

Использование match () [требует gawk]

#!/bin/bash

gawk '{
    while(match($0, /<U[0-9A-F]+>/)){
        pat = substr($0,RSTART,RLENGTH)
        gsub(/U0+|[<>]/,"",pat)
        asc = sprintf("%c", strtonum("0x"pat))
        $0 = substr($0, 1, RSTART-1) asc substr($0, RSTART+RLENGTH)
    }
}1' /path/to/infile
1 голос
/ 03 апреля 2011

Вот скрипт на Python, который преобразует <U9999> строки в их эквивалент ASCII (0-127), используя unidecode module :

#!/usr/bin/env python
import fileinput, re, sys
from unidecode import unidecode # to install, run: $ pip install unidecode

for line in fileinput.input(inplace='--inplace' in sys.argv):
    print re.sub(r'<U([0-9A-F]{4})>',
                 lambda m: unidecode(unichr(int(m.group(1), 16))),
                 line),

Он принимает ввод от stdin/ или файлы, указанные в командной строке.

$ u9999-to-ascii data.in
LC_TIME
abday   "Dom";"Seg";/
    "Ter";"Qua";/
    "Qui";"Sex";/
    "Sab"

Обратите внимание, что символа á нет, поскольку ascii его не поддерживает, поэтому скрипт заменил его на аналог ascii a.

Если вам не нужна ascii, тогда:

#!/usr/bin/env python
from __future__ import print_function
import fileinput, re, sys

for line in fileinput.input(mode='rb', inplace='--inplace' in sys.argv):
    print(re.sub(br'<U([0-9A-F]{4})>', lambda m: br'\u'+m.group(1),
                 line).decode('raw-unicode-escape'), end='')

Этот скрипт работает как в Python2.6 +, так и в Python3.x.Пример:

$ u9999-to-unicode.py data.in
LC_TIME
abday   "Dom";"Seg";/
    "Ter";"Qua";/
    "Qui";"Sex";/
    "Sáb"

Примечание. á.Этот скрипт может выдать ошибку, если ваша кодировка терминала не поддерживает все символы Юникода от data.in.В этом случае вы можете использовать метод .encode().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...