문맥(관심하지 않으시면 건너뛰세요. 제가 완전히 틀릴 것 같다면 계속 읽어보세요.)
메모리가 작은 임베디드 시스템의 경우 실제로 필요한 글리프만 포함된 글꼴을 생성하고 싶습니다. 따라서 빌드 시 언어 파일을 스캔하고 문자열에서 문자를 추출한 다음 해당 코드를 글꼴 생성 도구에 대한 인수로 사용해야 합니다.
관련 문자열이 포함된 번역 파일(물론 이것은 단지 예일 뿐이지만 적어도 일부 유니코드 내용을 다룹니다.)
TEXT_1=Foo
TEXT_2=Bar
TEXT_3=Baz
TEXT_4=Ünicødé
TEXT_5=ελληνικά
예상 출력
0x42,0x61,0x72,0x42,0x61,0x7A,0x46,0x6F,0x6F,0xDC,0x6E,0x69,0x63,0xF8,0x64,0xE9,0x3B5,0x3BB,0x3BB,0x3B7,0x3BD,0x3B9,0x3BA,0x3AC
지금까지의 나의 접근 방식
스크립트는 내가 설명한 작업을 수행합니다. 즉, sed
파일을 읽고, 문자열을 추출하고, 형식을 지정할 준비를 하고 printf
, sort -u
중복 항목을 제거합니다.
for char in $(sed "s/[^=]*=//;s/./'& /g" myLang.translation|sort -u); do
printf "0x%02X\n" $char
done
이 예에서는 작동하지만 실제 파일에서는 추악하고 신뢰할 수 없으며 버그가 있고 속도가 느릴 수 있습니다. 따라서 더 나은 도구, 더 나은 접근 방식, 더 나은 것을 지정할 수 있습니까?
답변1
그리고 perl
:
perl -C -lne '
if (/=(.*)/) {$c{$_}++ for split //, $1}
END{print join ",", map {sprintf "0x%X", ord$_} sort keys %c}
' your-file
다음을 제공합니다:
0x42,0x46,0x61,0x63,0x64,0x69,0x6E,0x6F,0x72,0x7A,0xDC,0xE9,0xF8,0x3AC,0x3B5,0x3B7,0x3B9,0x3BA,0x3BB,0x3BD
-C
로케일이 UTF-8을 문자 맵으로 사용하는 경우 UTF-8 I/O를 수행하십시오.-ln
sed -n
각 입력 줄에서 코드가 실행되는 모드입니다.-l
입력에서 줄 구분 기호를 제거하고 출력에 다시 추가합니다( 수행$\ = $/
).-e 'code'
스크립트가 아닌 명령줄에서 실행할 코드를 지정합니다./=(.*)/
일치시킬 행에는 하나 이상의 캡처(첫 번째 캡처 그룹)=
가 처음 발생한 이후의 내용이 포함됩니다.$1
split //, $1
빈 구분 기호를 사용하여 단일 문자로 분할합니다.$c{$_}++ for that-above
문자 목록을 반복하고 해당 연관 배열 요소를 증가시킵니다.%c
문자를 해당 항목에 매핑합니다. 여기서는 그 수를 사용하지 않습니다.END{code}
,code
끝까지 실행하는 것뿐입니다.sort keys %c
이 연관 배열의 키를 어휘적으로 정렬합니다.map { code } @list
각 요소에 코드를 적용하여 목록을 변환합니다.ord$_
문자의 숫자 값을 가져옵니다.sprintf "0x%X"
16진수(대문자 ABCDEF, 소문자 0x)로 형식을 지정합니다.join ",", @list
목록에 추가,
print
인쇄하고 그 뒤에$\
(개행 문자)를 입력하세요.
zsh에서는 (아마 훨씬 덜 효율적일 것입니다):
$ set -o cbases -o extendedglob
$ LC_COLLATE=C
$ echo ${(j[,])${(ous[])"$(<your-file cut -sd= -f2- | tr -d '\n')"}/(#m)?/$(([#16]#MATCH))}
0x42,0x46,0x61,0x63,0x64,0x69,0x6E,0x6F,0x72,0x7A,0xDC,0xE9,0xF8,0x3AC,0x3B5,0x3B7,0x3B9,0x3BA,0x3BB,0x3BD
또는 외부 유틸리티를 사용하지 않고:
$ set -o cbases -o extendedglob
$ LC_COLLATE=C
$ echo ${(j[,])${(@ous[])${(f)"$(<your-file)"}#*=}/(#m)?/$(([#16]#MATCH))}
0x42,0x46,0x61,0x63,0x64,0x69,0x6E,0x6F,0x72,0x7A,0xDC,0xE9,0xF8,0x3AC,0x3B5,0x3B7,0x3B9,0x3BA,0x3BB,0x3BD
"$(<you-file)"
IFS로 구분되지 않도록 후행 줄 바꿈을 제거하고 따옴표로 묶은 파일의 내용${(f)param}
행으로 분할f
하여 행을 목록으로 가져옵니다.${array#*=}
*=
배열 요소에서 가장 짧은 선행 부분 일치를 제거합니다.@
보장하기 위한 플래그 목록처리o
어휘 순서(C 로케일의 코드 포인트 기준)u
nique 중복 제거s[]
별도의 문자로 나눕니다.${array/(#m)?/$(([#16]#MATCH))}
감사( )에 캡처된 문자를?
16진수 형식의 값(산술 표현식에서)으로 바꿉니다. 이 옵션을 사용하면 다음을 수행할 수 있습니다.$MATCH
(#m)
#MATCH
[#16]
cbases
0xBEEF
16#BEEF
j[,]
에 참여하세요,
.
이를 별도의 단계로 나누면 더 명확해집니다.
set -o cbases -o extendedglob
LC_COLLATE=C
contents=$(<your-file)
lines=( ${(f)contents} )
values=( ${lines#*=} )
chars=( ${(@ous[])values} )
codepoints=( ${chars/(#m)?/$(( [#16] #MATCH ))} )
echo ${(j[,])codepoints}
답변2
작동해야 합니다 iconv | hexdump
.
샘플 입력에 대한 깔끔한 개념 증명:
cut -d= -f2- | iconv -t UTF-32LE | hexdump -ve '"0x%02X,"'
노트: 위 명령은 다음 환경에서 실행될 경우 예상대로 작동합니다.리틀 엔디안 방식x86 시리즈와 같은 CPU 아키텍처. 이 경고는 아래에 자세히 설명되어 있습니다.
코드 포인트를 통합하고 가짜 쉼표와 0x0A를 제거하려면 다음을 수행하세요.
cut -d= -f2- | sed 's/./&\
/g' | sort -u | tr -d '\n' | iconv -t UTF-32LE | hexdump -ve '",0x%02X"' | cut -d, -f2-
노트: 후자의 예에서 명령은 보다 이식 가능한 예를 제공하고 싶었기 때문에 sed
명령의 대체 부분에 개행 문자를 포함합니다 . s///
사용 중인 셸이 $'...'
리터럴 구문을 지원하는 경우 sed
전체 명령을 sed $'s/./&\\\n/g'
로 바꿔 동일한 줄에 개행 문자를 쉽게 포함할 수 있습니다. 리터럴 구문은 일반적으로 예제에서 사용하는 내장 함수에 대한 캐스트 매개변수를 지원하는 버전에서 사용할 수 있습니다 $'...'
.bash
'<char>
%X
printf
이 솔루션에 대한 몇 가지 참고 사항:
hexdump
CPU 엔디안: CPU 자체 엔디안에서는 고정 크기 정수만 처리할 수 있는 를 입력하므로iconv
이러한 요구 사항에 맞는 문자 스트림으로 변환해야 합니다.UTF-32LE
전체 유니코드 공간의 각 문자에 대한 고정 4바이트 인코딩이며 리틀 엔디안 형식으로 표현됩니다. 빅엔디안 CPU에서 명령을 실행해야 한다면 그렇게 할 수 있습니다iconv -t UTF-32BE
.- 위의 예에서는 입력이 다음을 사용하고 있다고 가정합니다.동일한 문자 세트 인코딩사용되었습니다저것구현하다현재 로케일, 귀하의 예에서와 같이. 관련된 인코딩을 일치시키지 않으려면
-f
옵션을 사용하여 입력 데이터의 인코딩을 명시적으로 지정하는 것이 좋지만iconv
가장 안전한 방법은 전환하는 것입니다.모두입력 데이터와 동일한 인코딩을 사용하는 로캘로 파이프합니다.cut
위 명령은=
문자를 감지해야 하므로sed
각 문자를 올바르게 감지해야 합니다.실재 - 변환 가용성: 호스트가
iconv
실제로 입력 데이터의 인코딩을 UTF32로 변환할 수 있는지 여부는 시스템에 따라 다릅니다. 적어도iconv
GNU(glibc)는 모든 "gconv 모듈"이 호스트 시스템에 설치되어 있을 때 매우 강력합니다. 위 명령의 경우 최소한 입력 데이터의 인코딩 및 UTF32 인코딩이 필요합니다. UTF8은 일반적으로 glibc 자체 기본libc
파일에 내장되어 있는 반면 UTF32 버전은 특정 gconv 모듈의 파일에 있습니다.so
. GNU glibc를 기반으로 하는 전형적인 성숙한 운영 체제에는 일반적으로 세계의 거의 모든 인코딩을 포괄하는 로드 가능한 gconv 모듈의 전체 세트가 함께 제공됩니다. - 변환 속도: GNU의
iconv
가장 일반적인 "삼각측량", 즉 입력 인코딩에서iconv
자체 내부 표현으로 변환한 다음 후자에서 원하는 출력 인코딩으로 변환합니다. 내가 아는 한 매우매우몇몇iconv
의 gconv 모듈은 중간 단계를 건너뛰고 한 인코딩에서 다른 인코딩으로 직접 변환을 제공합니다. 이 "삼각측량" 동작과cut | sed | sort
전체 파이프라인(등)에서 수행되는 보조 변환이iconv
GNU가 아닌(또는 전혀 변환하지 않는) 변환보다 빠른지 느린지는 알 수 없습니다 .iconv
마지막으로, 위에서 언급한 내용 중 어느 것도 대상 임베디드 시스템에 적용되지 않습니다. 솔루션은 일반적으로 강력하고 모든 기능을 갖춘 시스템에서 실행되어야 합니다.
답변3
사용행복하다(이전 Perl_6)
여기에서: https://docs.raku.org/언어/faq.html#String:_How_can_I_get_the_헥사데시말_representation_of_a_string%3F
~$ raku -ne 'BEGIN my %chars;
%chars{$_.encode.gist}++ for .split("=", limit => 2, :skip-empty)[1..*].comb;
END put .keys for %chars.sort;' file
#또는
~$ raku -ne 'BEGIN my %chars;
%chars{$_.encode.gist}++ for .comb(/<?after TEXT_ \d+ \= > .+ $/).comb;
END put .keys for %chars.sort;' file
ord
Raku(일명 Perl_6)에는 , ords
, unique
, printf
등과 같은 기능이 있지만 sprintf
위의 코드는 문서에서 직접 적용되었으므로 권장됩니다.
입력 예(하단에 추가 빈 줄이 있음):
TEXT_1=Foo
TEXT_2=Bar
TEXT_3=Baz
TEXT_4=Ünicødé
TEXT_5=ελληνικά
예제 출력:
utf8:0x<42>
utf8:0x<46>
utf8:0x<61>
utf8:0x<63>
utf8:0x<64>
utf8:0x<69>
utf8:0x<6E>
utf8:0x<6F>
utf8:0x<72>
utf8:0x<7A>
utf8:0x<C3 9C>
utf8:0x<C3 A9>
utf8:0x<C3 B8>
utf8:0x<CE AC>
utf8:0x<CE B5>
utf8:0x<CE B7>
utf8:0x<CE B9>
utf8:0x<CE BA>
utf8:0x<CE BB>
utf8:0x<CE BD>
utf8
위에서 본 것과 같이 Raku가 기본적으로 사용됩니다. 그러나 @StephaneChazelas의 Perl(5) 답변과 동일한 결과를 얻기 위해 .encode("utf-16")
이러한 결과를 반환 할 수 있습니다..values
~$ raku -e 'my @a = lines>>.subst(:global, / ^^ <(TEXT_ \d+ \= )> /).join.comb.unique; \
print join ",", map {sprintf("0x%X", .encode("utf-16").values) }, @a[].sort;'
0x42,0x46,0x61,0x63,0x64,0x69,0x6E,0x6F,0x72,0x7A,0xDC,0xE9,0xF8,0x3AC,0x3B5,0x3B7,0x3B9,0x3BA,0x3BB,0x3BD
원한다면 아래의 두 번째 링크에서 유니코드 정규화(Raku)에 대해 매우 광범위한 논의를 할 수 있습니다. 해당 페이지에서 원시 바이트를 복구해야 하는 경우 인코딩 utf8-c8
(예: "utf8-clean8")을 사용할 수 있습니다.
https://docs.raku.org/언어/faq.html#String:_How_can_I_get_the_헥사데시말_representation_of_a_string%3F
https://docs.raku.org/언어/unicode
https://raku.org
답변4
내 원래 질문에 대한 답변을 제공했지만(그 중 하나를 수락하겠습니다) 완전성을 위해 python
일부 변경 사항(형식 정의 변경, 부사 문자 모양은 다음과 같이 그룹화되어야 함) 을 추가했습니다.0x30-0x39
#!/bin/python3
# glycol is the GLYph COLlector
# it collects all used glyphs from the translation json files given as command line arguments
# and prints them as a string formatted to be used as -r argument for lv_font_conv
# Usage: lv_font_conv -r $(glycol de.json en.json fr.json) ...
import sys
Glyphs=[]
# Loop over all files
sys.argv.pop(0)
for file in sys.argv:
# Sorry, low level tool without error handling
with open(file, 'r', encoding="utf-8") as f:
for line in f:
parts = line.split('"')
if len(parts) == 5:
# expect format _"key":"string" -- No json parsing
Glyphs.extend(ord(c) for c in parts[3])
Glyphs.sort()
# Now loop over the sorted glyph list, skip duplicates, join regions
last=0
region=0
for glyph in Glyphs:
if (last == 0):
print(hex(glyph), end='')
elif (glyph == last + 1):
region = glyph
elif (glyph > last):
if (region == last):
print('-'+ hex(region), end='')
print(','+ hex(glyph), end='')
last = glyph
if (region == last):
print('-'+ hex(region), end='')
print()