Скрипт для преобразования символов ASCII в нотацию "<Uxxx>" - PullRequest
2 голосов
/ 03 апреля 2011

Я делаю некоторые изменения в файлах локали Linux /usr/share/i18n/locales (например, pt_BR), и необходимо, чтобы строки формата (например, %d-%m-%Y %H:%M) были указаны в Unicode, где каждая (в данном случае ASCII)символ представляется как <U00xx>.

Таким образом, текст, подобный этому:

LC_TIME
d_t_fmt "%a %d %b %Y %T %Z"
d_fmt   "%d-%m-%Y"
t_fmt   "%T"

Должен быть:

LC_TIME
d_t_fmt "<U0025><U0061><U0020><U0025><U0064><U0020><U0025><U0062><U0020><U0025><U0059><U0020><U0025><U0054><U0020><U0025><U005A>"
d_fmt   "<U0025><U0064><U002D><U0025><U006D><U002D><U0025><U0059>"
t_fmt   "<U0025><U0054>"

Таким образом, мне нужен сценарий командной строки (будь то bash, Python, Perl или что-то еще), который будет принимать данные типа %d-%m-%Y и преобразовывать их в <U0025><U0064><U002D><U0025><U006D><U002D><U0025><U0059>.

Все символы во входной строке будут символами ASCII (из 0x20на 0x7F), так что это на самом деле причудливое преобразование "char-to-hex-string".

Может кто-нибудь помочь мне?Мои навыки в bash-скриптинге очень ограничены, а в Python еще хуже.

Бонус за элегантные, объясненные решения.

Спасибо!

(кстати, это будет "обратный" скрипт для моего предыдущего вопроса )

Ответы [ 4 ]

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

Каждый символ с вводом файла

Если вы хотите преобразовать каждый символ файла в представление Unicode, то это будет простой однострочный

while IFS= read -r -n1 c;do printf "<U%04X>" "'$c"; done < ./infile

Каждый символ на STDIN

Если вы хотите создать Unix-подобный инструмент, который преобразует ввод на STDIN в Unicode-подобный вывод, используйте это:

uni(){ c=$(cat); for((i=0;i<${#c};i++)); do printf "<U%04X>" "'${c:i:1}"; done; }

Подтверждение концепции

$ echo "abc" | uni
<U0061><U0062><U0063>

Только символы между двойными кавычками

#!/bin/bash

flag=0
while IFS= read -r -n1 c; do
    if [[ "$c" == '"' ]]; then
        ((flag^=1))
        printf "%c" "$c"
    elif [[ "$c" == $'\0' ]]; then
        echo
    elif ((flag)); then
        printf "<U%04X>" "'$c"
    else
        printf "%c" "$c"
    fi
done < /path/to/infile

Подтверждение концепции

$ cat ./unime
LC_TIME
d_t_fmt "%a %d %b %Y %T %Z"
d_fmt   "%d-%m-%Y"
t_fmt   "%T"
abday "Dom";"Seg";/
here is a string with "multiline
quotes";/

$ ./uni.sh
LC_TIME
d_t_fmt "<U0025><U0061><U0020><U0025><U0064><U0020><U0025><U0062><U0020><U0025><U0059><U0020><U0025><U0054><U0020><U0025><U005A>"
d_fmt   "<U0025><U0064><U002D><U0025><U006D><U002D><U0025><U0059>"
t_fmt   "<U0025><U0054>"
abday "<U0044><U006F><U006D>";"<U0053><U0065><U0067>";/
here is a string with "<U006D><U0075><U006C><U0074><U0069><U006C><U0069><U006E><U0065>
<U0071><U0075><U006F><U0074><U0065><U0073>";/

Объяснение

Довольнопросто реально

  1. while IFS= read -r -n1 c;: перебирайте ввод по одному символу за раз (через -n1) и сохраняйте символ в переменной c.Здесь есть флаги IFS= и -r, поэтому встроенная команда read не пытается разделить слова или интерпретировать escape-последовательности соответственно.
  2. if [[ "$c" == '"' ]];: если текущий символ двойная кавычка
  3. ((flag^=1)): инвертировать значение флага из 0-> 1 или 1-> 0
  4. elif [[ "$c" == $'\0' ]];: если текущим символом является NUL, то echo символ новой строки
  5. elif ((flag)): если флаг равен 1, выполнить транслитерацию в юникоде
  6. printf "<U%04X>" "'$c": магия, котораявыполняет транслитерацию Unicode.Обратите внимание, что одинарная кавычка перед $c является обязательной, поскольку она сообщает printf, что мы присваиваем ей ASCII-представление числа.
  7. else printf "%c" "$c": выводим символ без транслитерации в Юникоде
5 голосов
/ 03 апреля 2011

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

#!/usr/bin/env python3.2
import sys
text = sys.argv[1]
encoded = "".join("<U{0:04X}>".format(ord(char)) for char in text)
print(encoded)

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

$ python3 file.py "enter_input"
<U0065><U006E><U0074><U0065><U0072><U005F><U0069><U006E><U0070><U0075><U0074>

(Один и тот же скрипт должен работать как для Python 3.x, так и для 2.x. Просто измените версию в shebang к тому, что у вас есть.)

Пояснение:

  1. Нам нужно импортировать модуль sys для чтения аргументов командной строки.

  2. Список sys.argv - это список всех аргументов командной строки. Запись [0] - это имя программы, запись [1] - первый аргумент и т. Д.

  3. f(char) for char in text является выражением генератора . Он зациклится для каждого символа в переменной text, затем применит к нему функцию f и, наконец, соберет результат в виде отложенного списка ( iterable ).

  4. ord(char) находит кодовую точку Unicode символа.

  5. "<U{0:04X}>".format(x) - это метод форматирования строки, описанный именем. Строка форматирования принимает 1 ввод x и форматирует в формат 04X , что означает начальный ноль, ширину 4, шестнадцатеричный верхний регистр.

  6. "".join(it) объединяет все элементы в ленивом списке (итерируемый) it. "" означает, что разделитель является пустой строкой.

  7. print(encoded) записать строку encoded в стандартный вывод.

0 голосов
/ 26 февраля 2015

Решение сценария оболочки:

#!/bin/sh

while IFS= read -r -n1 c;
    do printf "<U%04X>" "'$c";
done

Это читает стандартный ввод и печатает на стандартный вывод (при условии, что вы поместили скрипт в исполняемый файл toUnicode.sh ):

> echo "hello" | toUnicode.sh
<U0068><U0065><U006C><U006C><U006F><U0000>

Это печатает символ EOF (<U0000>), но вы можете изменить этот сценарий в соответствии со своими потребностями, хотите ли вы читать входные данные по одной строке за раз, или обрезать их, или изменить его другим способом.

0 голосов
/ 25 октября 2011

echo -n "aä" | ruby -KU -e '$<.chars{|c| print "<U"+"%04X"%c.unpack("U*")[0]+">"}; puts'

Выходы <U0061><U00E4>

-KU = $KCODE = "U"

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