ฉันจะรับค่า ASCII ของตัวอักษรได้อย่างไร
ตัวอย่างเช่น97
เพื่อa
?
ฉันจะรับค่า ASCII ของตัวอักษรได้อย่างไร
ตัวอย่างเช่น97
เพื่อa
?
คำตอบ:
กำหนดฟังก์ชั่นทั้งสองนี้ (โดยปกติจะมีในภาษาอื่น):
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"
สิ่งที่ต้องทำ?
คุณสามารถดูทั้งชุดด้วย:
$ man ascii
คุณจะได้รับตารางเป็นฐานแปดฐานสิบและทศนิยม
หากคุณต้องการขยายเป็นอักขระ UTF-8:
$ perl -CA -le 'print ord shift' 😈
128520
$ perl -CS -le 'print chr shift' 128520
😈
ด้วยbash
, ksh
หรือzsh
builtins:
$ printf "\U$(printf %08x 128520)\n"
😈
มันใช้งานได้ดี
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
ไม่ได้อยู่ใน echos ที่สอดคล้องกับ Unix 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 บิต(น้อยกว่าNUL
)แบ่งออกเป็นสี่สตริงที่ยกมาเชลล์แบ่งเท่า ๆ กันที่ขอบเขต 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#?}"}"
จากนั้นทำการวนซ้ำการบันทึกหากจำเป็นและหลังจากนั้นจะกำหนดบริบทโลแคลปัจจุบันเป็นโลแคล C สำหรับทุกหมวดหมู่โดยกำหนดให้กับLC_ALL
ตัวแปร จากจุดนี้เป็นต้นไปอักขระสามารถประกอบด้วยไบต์เดียวเท่านั้นดังนั้นหากมีหลายไบต์ในอักขระตัวแรกของอาร์กิวเมนต์แรกตอนนี้อักขระเหล่านี้ควรสามารถระบุแอดเดรสแต่ละตัวเป็นอักขระแต่ละตัวในสิทธิของตนเอง
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
ทดแทนคำสั่งทั้งสองรูปแบบ ฟังก์ชั่นนี้ไม่เคยเรียก subshell หรือคำสั่งอื่น ๆ มันจะยังไม่เคยพยายามที่จะอ่านหรือเขียนอินพุต / เอาต์พุต(ยกเว้นในกรณีของบางข้อความวินิจฉัยเปลือก - ซึ่งอาจบ่งชี้ข้อผิดพลาด)
โปรดทราบด้วยว่าการทดสอบความต่อเนื่องของวงไม่ได้เป็นเพียง[ -n "$a" ]
เพราะฉันพบกับความยุ่งยากของฉันด้วยเหตุผลบางอย่างที่bash
เชลล์ทำ:
char=$(printf \\1)
[ -n "$char" ] || echo but it\'s not null\!
but it's not null!
... และดังนั้นฉันอย่างชัดเจนเปรียบเทียบ$a
's len 0 สำหรับแต่ละซ้ำซึ่งยังลึกลับทำงานแตกต่างกัน(อ่าน: ถูกต้อง)
case
ตรวจสอบไบต์แรกเพื่อรวมไว้ในใด ๆ $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)))|"
ณ จุดนี้ค่าของไบต์(modulo 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
- ว่าฟังก์ชั่นที่ได้รับผลกระทบตลอดระยะเวลาการดำเนินการของมันจะถูกเรียกคืนสู่สถานะก่อนหน้า - ไม่ว่าจะตั้งค่าและไม่เป็นโมฆะตั้งค่าและเป็นโมฆะ เพื่อ$OPTARG
เป็นฟังก์ชันส่งคืน ค่าส่งคืนที่แท้จริงคือหนึ่งน้อยกว่าจำนวนไบต์ทั้งหมดในอักขระตัวแรกของอาร์กิวเมนต์แรกดังนั้นอักขระไบต์เดี่ยวใด ๆ จะคืนค่าศูนย์และอักขระหลายไบต์ใด ๆ จะส่งกลับมากกว่าศูนย์ - และรูปแบบผลลัพธ์จะแปลกเล็กน้อย
ค่า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
ฉันอาจจะทำมากกว่าพิมพ์เพียง char ต่อบรรทัด แต่สิ่งที่เป็นไปได้ ในกรณีใด ๆ ผมยังไม่ได้พบgetopts
ว่าถูกต้องจะทำ(ตีว่า - dash
's 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
เวิร์กโฟลว์แบบนั้น - ไบต์สำหรับไบต์ / อักขระชนิดถ่าน - เป็นสิ่งที่ฉันมักจะได้รับเมื่อทำสิ่ง 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
ภาษาคำสั่งPOSIX bash
เป็นbourne supraset อีกครั้งเหมือนกันและในส่วนใหญ่ motipator สูงชันสำหรับมากของการดูแลจ่ายไปด้านบนแบบพกพาอย่างกว้างขวางขยายตัวเองและเนมสเปซขนาดตัวอักษรเกียรติทุกชนิด 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
konsole
xxd<press enter>
<SHIFT+INSERT><CTRL+D>
คุณได้รับสิ่งที่ชอบ:
mariank@dd903c5n1 ~ $ xxd
û0000000: fb
คุณรู้ว่าสัญลักษณ์ที่คุณวางมีรหัสฐานสิบหก 0xfb
"'A"
ถูกต้องในขณะที่ถ้าคุณใช้มันจะพูดว่า:"A"
A: invalid number
ดูเหมือนว่ามันจะทำในด้าน printf (เช่นในเปลือก"'A"
เป็น 2 ตัวอักษร, a'
และ aA
. เหล่านั้นจะถูกส่งไปยัง printf และในบริบท printf ก็จะถูกแปลงเป็นค่า ASCII ของ A, และในที่สุดก็ถูกพิมพ์ เป็นทศนิยมขอบคุณ'%d'
. ใช้'Ox%x'
เพื่อแสดงใน hexa หรือ'0%o'
ให้เป็นแปด))