답변:
이 두 기능을 정의하십시오 (보통 다른 언어로 사용 가능).
chr() {
[ "$1" -lt 256 ] || return 1
printf "\\$(printf '%03o' "$1")"
}
ord() {
LC_CTYPE=C printf '%d' "'$1"
}
용법:
chr 65
A
ord A
65
printf "\\$(printf '%03o' "$1")"
, '%03o'
, LC_CTYPE=C
과에서 따옴표 "'$1"
합니까?
UTF-8 문자로 확장하려는 경우 :
$ perl -CA -le 'print ord shift' 😈
128520
$ perl -CS -le 'print chr shift' 128520
😈
와 bash
, ksh
또는 zsh
내장 명령 :
$ printf "\U$(printf %08x 128520)\n"
😈
iceweasel
에 Debian sid
. iceweasel의 웹 콘솔에서 확인 된 글꼴은 "같은데요 산세"내가에서 상류로 데비안에서 온 설치 TTF-데자뷰 TTF-데자뷰 코어 TTF-데자뷰 - 추가 패키지있어 dejavu-fonts.org을
이것은 잘 작동합니다.
echo "A" | tr -d "\n" | od -An -t uC
echo "A" ### Emit a character.
| tr -d "\n" ### Remove the "newline" character.
| od -An -t uC ### Use od (octal dump) to print:
### -An means Address none
### -t select a type
### u type is unsigned decimal.
### C of size (one) char.
정확히 다음과 같습니다.
echo -n "A" | od -An -tuC ### Not all shells honor the '-n'.
echo -n
에 대한 필요성을 없애 줄 바꿈 후행 억제합니다tr -d "\n"
echo
은 유닉스 호환 반향이 아닌 일부 구현 만 가능 합니다. printf %s A
휴대용 것입니다.
간단하고 우아한 Bash 솔루션을 사용하려고합니다.
for i in {a..z}; do echo $(printf "%s %d" "$i" "'$i"); done
스크립트에서 다음을 사용할 수 있습니다.
CharValue="A"
AscValue=`printf "%d" "'$CharValue"
CharValue 앞에 작은 따옴표가 있습니다. 의무입니다 ...
printf "%d"
입니다.
ctbl() for O in 0 1 2 3
do for o in 0 1 2 3 4 5 6 7
do for _o in 7 6 5 4 3 2 1 0
do case $((_o=(_o+=O*100+o*10)?_o:200)) in
(*00|*77) set "${1:+ \"}\\$_o${1:-\"}";;
(140|42) set '\\'"\\$_o$1" ;;
(*) set "\\$_o$1" ;esac
done; printf "$1"; shift
done
done
eval '
ctbl(){
${1:+":"} return "$((OPTARG=0))"
set "" "" "${1%"${1#?}"}"
for c in ${a+"a=$a"} ${b+"b=$b"} ${c+"c=$c"}\
${LC_ALL+"LC_ALL=$LC_ALL"}
do while case $c in (*\'\''*) ;; (*) ! \
set "" "${c%%=*}='\''${c#*=}$1'\'' $2" "$3"
esac;do set "'"'\''\${c##*\'}"'$@"; c=${c%\'\''*}
done; done; LC_ALL=C a=$3 c=;set "" "$2 OPTARG='\''${#a}*("
while [ 0 -ne "${#a}" ]
do case $a in ([[:print:][:cntrl:]]*)
case $a in (['"$(printf \\1-\\77)"']*)
b=0;; (*) b=1
esac;; (['"$( printf \\200-\\277)"']*)
b=2;; (*) b=3
esac; set '"$(ctbl)"' "$@"
eval " set \"\${$((b+1))%"'\''"${a%"${a#?}"}"*}" "$6"'\''
a=${a#?};set "$((b=b*100+${#1}+${#1}/8*2)))" \
"$2(o$((c+=1))=$b)>=(d$c=$((0$b)))|"
done; eval " unset LC_ALL a b c;${2%?})'\''"
return "$((${OPTARG%%\**}-1))"
}'
첫 번째 ctbl()
-맨 위에는 한 번만 실행됩니다. 다음과 같은 출력을 생성합니다 ( sed -n l
인쇄 성 을 위해 필터링 됨 ) .
ctbl | sed -n l
"\200\001\002\003\004\005\006\a\b\t$
\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\
\035\036\037 !\\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRS\
TUVWXYZ[\\]^_\\`abcdefghijklmnopqrstuvwxyz{|}~\177" "\200\201\202\203\
\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\
\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\
\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\
\267\270\271\272\273\274\275\276\277" "\300\301\302\303\304\305\306\
\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\
\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\
\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\
\372\373\374\375\376\377"$
... 모든 8 비트 바이트 (less NUL
) 이며 4 개의 쉘 인용 문자열로 나뉘어 64 바이트 경계에서 균등하게 분할됩니다. 문자열은 같은 범위 진수로 표현 될 수있는 \200\1-\77
, \100-\177
, \200-\277
, \300-\377
바이트 (128)를위한 장소 홀더로서 사용된다 NUL
.
ctbl()
존재 의 첫 번째 목적은 문자열을 생성 eval
하여 두 번째 ctbl()
함수를 문자 그대로 내장 한 후에 정의하는 것입니다. 그렇게하면 필요할 때마다 다시 생성 할 필요없이 함수에서 참조 할 수 있습니다. eval
두 번째 ctbl()
함수를 정의 할 때 첫 번째 함수는 중단됩니다.
두 번째 ctbl()
함수의 상반부 는 대부분 부수적입니다. 호출 될 때 영향을 줄 수있는 현재 쉘 상태를 이식 가능하고 안전하게 직렬화하도록 설계되었습니다. 맨 위 루프는 사용하려는 변수의 값에 따옴표를 인용 한 다음 모든 결과를 위치 매개 변수에 누적합니다.
그러나 처음 두 줄은 먼저 즉시 0을 반환 $OPTARG
하고 함수의 첫 번째 인수에 하나 이상의 문자가 포함되어 있지 않으면 동일하게 설정 됩니다. 그리고 두 번째 줄은 첫 번째 인수 만 첫 번째 문자로만 잘립니다. 함수는 한 번에 한 문자 만 처리하기 때문입니다. 중요한 것은 현재 로케일 컨텍스트에서이를 수행합니다. 즉, 문자가 하나 이상의 바이트를 포함 할 수있는 경우 쉘이 멀티 바이트 문자를 올바르게 지원하는 경우에는 바이트가 아닌 문자를 제외한 모든 바이트를 버리지 않습니다. 첫 번째 인수의 첫 번째 문자.
${1:+":"} return "$((OPTARG=0))"
set "" "" "${1%"${1#?}"}"
그런 다음, 필요한 경우 저장 루프를 수행 한 후 LC_ALL
변수 에 지정하여 모든 카테고리의 현재 로케일 컨텍스트를 C 로케일로 재정의합니다 . 이제부터 문자는 단일 바이트로만 구성 될 수 있으므로 첫 번째 인수의 첫 번째 문자에 여러 바이트가있는 경우 이제 각 문자를 개별 문자로 지정할 수 있습니다.
LC_ALL=C
이러한 이유로 함수의 후반부 는 단일 실행 시퀀스와 달리 while
루프 입니다. 대부분의 경우 호출 당 한 번만 실행되지만, ctbl()
정의 된 쉘 이 멀티 바이트 문자를 올바르게 처리하면 루프 될 수 있습니다 .
while [ 0 -ne "${#a}" ]
do case $a in ([[:print:][:cntrl:]]*)
case $a in (['"$(printf \\1-\\77)"']*)
b=0;; (*) b=1
esac;; (['"$( printf \\200-\\277)"']*)
b=2;; (*) b=3
esac; set '"$(ctbl)"' "$@"
위의 $(ctbl)
명령 대체는 eval
함수가 처음 정의 될 때 까지 한 번만 평가되며 해당 토큰 이후에는 쉘의 메모리에 저장된 명령 대체의 리터럴 출력으로 대체됩니다. 두 case
패턴 명령 대체도 마찬가지입니다 . 이 함수는 서브 쉘이나 다른 명령을 호출하지 않습니다. 또한 버그를 나타내는 쉘 진단 메시지의 경우를 제외하고는 입출력을 읽거나 쓰려고 시도하지 않습니다 .
또한 루프 연속성에 대한 테스트는 간단하지 않습니다 [ -n "$a" ]
. 왜냐하면 필자가 좌절감을 느낀 것처럼 어떤 이유로 bash
쉘이 수행하기 때문입니다.
char=$(printf \\1)
[ -n "$char" ] || echo but it\'s not null\!
but it's not null!
... 따라서 $a
각 반복마다 len을 0 과 명시 적으로 비교 합니다 .
이 case
검사는 4 개의 문자열에 포함 할 첫 번째 바이트를 확인하고에 설정된 바이트에 대한 참조를 저장합니다 $b
. 그 후 쉘의 첫 번째 네 개의 위치 매개 변수는 선행 문자에 의해 set
포함되고 eval
작성된 문자열에 대한 것 ctbl()
입니다.
다음으로, 첫 번째 인수의 나머지 부분이 다시 첫 번째 문자로 일시적으로 잘립니다. 이제 단일 바이트 여야합니다. 첫 번째 바이트가 유사한 캐릭터와의 기준의 말미에서 제거하기위한 기준으로 사용된다 $b
이다 eval
문자열의 마지막 바이트 기준 바이트에서부터 멀리 치환 될 수 있도록 위치 파라미터를 나타내는 'D. 다른 세 문자열은 위치 매개 변수에서 완전히 삭제됩니다.
eval " set \"\${$((b+1))%"'\''"${a%"${a#?}"}"*}" "$6"'\''
a=${a#?};set "$((b=b*100+${#1}+${#1}/8*2)))" \
"$2(o$((c+=1))=$b)>=(d$c=$((0$b)))|"
이 시점에서 바이트 값 (모듈로 64) 은 문자열의 len으로 참조 될 수 있습니다.
str=$(printf '\200\1\2\3\4\5\6\7')
ref=$(printf \\4)
str=${str%"$ref"*}
echo "${#str}"
4
그런 다음의 값을 기반으로 모듈러스를 조정하기 위해 약간의 수학이 수행되고 $b
첫 번째 바이트 $a
가 영구적으로 제거되고 루프 $a
가 실제로 비어 있는지 확인하기 위해 현재 사이클의 출력이 완료 대기중인 스택에 추가됩니다 .
eval " unset LC_ALL a b c;${2%?})'\''"
return "$((${OPTARG%%\**}-1))"
경우에는 $a
예외로 - 확실히 모든 이름과 상태, 비어 $OPTARG
의 실행의 과정을 통해 영향을받는 기능은 이전 상태로 복원되었는지 - - 세트와 null가 아닌이 설정하고 널 (null) 또는 해제 여부 - 출력 저장 에 $OPTARG
함수가 반환한다. 실제 반환 값은 첫 번째 인수의 첫 번째 문자에있는 총 바이트 수보다 1이 적습니다. 따라서 단일 바이트 문자는 0을 반환하고 모든 멀티 바이트 문자는 0보다 큰 값을 반환하므로 출력 형식이 약간 이상합니다.
값 ctbl()
에 저장 $OPTARG
평가하는 경우, 병행 형태의 변수 명을 설정 한 것을 유효한 쉘의 산술 표현식은 $o1
, $d1
, $o2
, $d2
십진수와 첫번째 인수의 선두 문자의 모든 각 바이트 진수 값하지만 결국 총 평가 첫 번째 인수의 바이트 수 이 글을 쓸 때 특정 종류의 워크 플로를 염두에 두었고 시연이 좋을 것 같습니다.
종종 getopts
다음 과 같이 문자열을 분리 해야하는 이유를 찾습니다 .
str=some\ string OPTIND=1
while getopts : na -"$str"
do printf %s\\n "$OPTARG"
done
s
o
m
e
s
t
r
i
n
g
아마 한 줄에 문자를 인쇄하는 것보다 조금 더 할 것이지만 가능합니다. 어떤 경우에, 나는 아직 발견되지 않은 getopts
제대로 할 것을 - (저를 공격 dash
의는 getopts
이 문자로 숯불 않지만, bash
확실히하지 않습니다) :
str=ŐőŒœŔŕŖŗŘřŚśŜŝŞş OPTIND=1
while getopts : na -"$str"
do printf %s\\n "$OPTARG"
done| od -tc
0000000 305 \n 220 \n 305 \n 221 \n 305 \n 222 \n 305 \n 223 \n
0000020 305 \n 224 \n 305 \n 225 \n 305 \n 226 \n 305 \n 227 \n
0000040 305 \n 230 \n 305 \n 231 \n 305 \n 232 \n 305 \n 233 \n
0000060 305 \n 234 \n 305 \n 235 \n 305 \n 236 \n 305 \n 237 \n
0000100
승인. 그래서 시도했습니다 ...
str=ŐőŒœŔŕŖŗŘřŚśŜŝŞş
while [ 0 -ne "${#str}" ]
do printf %c\\n "$str" #identical results for %.1s
str=${str#?}
done| od -tc
#dash
0000000 305 \n 220 \n 305 \n 221 \n 305 \n 222 \n 305 \n 223 \n
0000020 305 \n 224 \n 305 \n 225 \n 305 \n 226 \n 305 \n 227 \n
0000040 305 \n 230 \n 305 \n 231 \n 305 \n 232 \n 305 \n 233 \n
0000060 305 \n 234 \n 305 \n 235 \n 305 \n 236 \n 305 \n 237 \n
0000100
#bash
0000000 305 \n 305 \n 305 \n 305 \n 305 \n 305 \n 305 \n 305 \n
*
0000040
그런 종류의 워크 플로우-char 종류의 byte / char 바이트는 tty 작업을 할 때 자주 사용되는 워크 플로우입니다. 입력의 최첨단에서는 문자 값을 읽 자마자 알아야하며 크기 (특히 열을 계산할 때) 가 필요하며 문자가 전체 문자 가되어야 합니다.
그리고 지금은 ctbl()
:
str=ŐőŒœŔŕŖŗŘřŚśŜŝŞş
while [ 0 -ne "${#str}" ]
do ctbl "$str"
printf "%.$(($OPTARG))s\t::\t$OPTARG\t::\t$?\t::\t\\$o1\\$o2\n" "$str"
str=${str#?}
done
Ő :: 2*((o1=305)>=(d1=197)|(o2=220)>=(d2=144)) :: 1 :: Ő
ő :: 2*((o1=305)>=(d1=197)|(o2=221)>=(d2=145)) :: 1 :: ő
Œ :: 2*((o1=305)>=(d1=197)|(o2=222)>=(d2=146)) :: 1 :: Œ
œ :: 2*((o1=305)>=(d1=197)|(o2=223)>=(d2=147)) :: 1 :: œ
Ŕ :: 2*((o1=305)>=(d1=197)|(o2=224)>=(d2=148)) :: 1 :: Ŕ
ŕ :: 2*((o1=305)>=(d1=197)|(o2=225)>=(d2=149)) :: 1 :: ŕ
Ŗ :: 2*((o1=305)>=(d1=197)|(o2=226)>=(d2=150)) :: 1 :: Ŗ
ŗ :: 2*((o1=305)>=(d1=197)|(o2=227)>=(d2=151)) :: 1 :: ŗ
Ř :: 2*((o1=305)>=(d1=197)|(o2=230)>=(d2=152)) :: 1 :: Ř
ř :: 2*((o1=305)>=(d1=197)|(o2=231)>=(d2=153)) :: 1 :: ř
Ś :: 2*((o1=305)>=(d1=197)|(o2=232)>=(d2=154)) :: 1 :: Ś
ś :: 2*((o1=305)>=(d1=197)|(o2=233)>=(d2=155)) :: 1 :: ś
Ŝ :: 2*((o1=305)>=(d1=197)|(o2=234)>=(d2=156)) :: 1 :: Ŝ
ŝ :: 2*((o1=305)>=(d1=197)|(o2=235)>=(d2=157)) :: 1 :: ŝ
Ş :: 2*((o1=305)>=(d1=197)|(o2=236)>=(d2=158)) :: 1 :: Ş
ş :: 2*((o1=305)>=(d1=197)|(o2=237)>=(d2=159)) :: 1 :: ş
참고 ctbl()
실제로 정의하지 않습니다 $[od][12...]
이 어떤 상태에 어떤 지속적인 영향을 미치지 않습니다하지만 결코 - 변수 $OPTARG
-하지만이의 문자열을두고 $OPTARG
그 사용할 수 있습니다 위의 수행하여 내가 각 문자의 두 번째 사본을 얻을 방법이다 -을 정의 할 수 printf "\\$o1\\$o2"
있기 때문에 내가 평가할 때마다 설정됩니다 $(($OPTARG))
. 하지만 그것을 어디에 나 또한 필드 길이 수정을 선언하고있어 printf
'의 %s
캐릭터 라인의 인수 형식과 표현이 항상 문자 바이트의 총 숫자로 평가하기 때문에 내가 할 때, 나는 출력에 전체 문자를 얻을 :
printf %.2s "$str"
[ "$(printf \\1)" ]|| ! echo but its not null!
한다면 실제 대회를 추천하지 않는 한, 의미있는 의견 연습에 익숙해 지도록 자유롭게 참고하십시오 .
sh
명령 언어입니다. bash
본은 다시 동일 하게 상복 된 본이며, 대체로 휴대가 용이하고 자체 확장되며 모든 종류의 명목상의 캐릭터 크기를 향한 많은 관심에 대한 강력한 동기 부여입니다. bash
이 중 많은 부분을 이미 처리해야하지만 c
언어 printf
는 위의 기능이 부족했을 수도 있습니다.
쉘 스크립트는 아니지만 작동
awk 'BEGIN{for( i=97; i<=122;i++) printf "%c %d\n",i,i }'
샘플 출력
xieerqi:$ awk 'BEGIN{for( i=97; i<=122;i++) printf "%c %d\n",i,i }' | head -n 5
a 97
b 98
c 99
d 100
e 101
"'A"
하는 경우 : 맞지만, 사용하면 다음과 같이"A"
말할 수 있습니다A: invalid number
. 그것은 printf면에서 수행 된 것처럼 보입니다 (즉, 쉘에서"'A"
실제로 2 개의 문자 a'
와 aA
입니다. 받는 소수 감사로'%d'
사용합니다.'Ox%x'
헥사에이를 표시하거나'0%o'
8 진수로 그것을 가지고))