mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-01 05:16:05 +01:00
af5a85f363
28340: assignment to range of scalar variable with multibyte characters
467 lines
11 KiB
Text
467 lines
11 KiB
Text
%prep
|
||
|
||
# Find a UTF-8 locale.
|
||
setopt multibyte
|
||
# Don't let LC_* override our choice of locale.
|
||
unset -m LC_\*
|
||
mb_ok=
|
||
langs=(en_{US,GB}.{UTF-,utf}8 en.UTF-8
|
||
$(locale -a 2>/dev/null | egrep 'utf8|UTF-8'))
|
||
for LANG in $langs; do
|
||
if [[ é = ? ]]; then
|
||
mb_ok=1
|
||
break;
|
||
fi
|
||
done
|
||
if [[ -z $mb_ok ]]; then
|
||
ZTST_unimplemented="no UTF-8 locale or multibyte mode is not implemented"
|
||
else
|
||
print -u $ZTST_fd Testing multibyte with locale $LANG
|
||
mkdir multibyte.tmp && cd multibyte.tmp
|
||
fi
|
||
|
||
%test
|
||
|
||
a=ténébreux
|
||
for i in {1..9}; do
|
||
print ${a[i]}
|
||
for j in {$i..9}; do
|
||
print $i $j ${a[i,j]} ${a[-j,-i]}
|
||
done
|
||
done
|
||
0:Basic indexing with multibyte characters
|
||
>t
|
||
>1 1 t x
|
||
>1 2 té ux
|
||
>1 3 tén eux
|
||
>1 4 téné reux
|
||
>1 5 ténéb breux
|
||
>1 6 ténébr ébreux
|
||
>1 7 ténébre nébreux
|
||
>1 8 ténébreu énébreux
|
||
>1 9 ténébreux ténébreux
|
||
>é
|
||
>2 2 é u
|
||
>2 3 én eu
|
||
>2 4 éné reu
|
||
>2 5 énéb breu
|
||
>2 6 énébr ébreu
|
||
>2 7 énébre nébreu
|
||
>2 8 énébreu énébreu
|
||
>2 9 énébreux ténébreu
|
||
>n
|
||
>3 3 n e
|
||
>3 4 né re
|
||
>3 5 néb bre
|
||
>3 6 nébr ébre
|
||
>3 7 nébre nébre
|
||
>3 8 nébreu énébre
|
||
>3 9 nébreux ténébre
|
||
>é
|
||
>4 4 é r
|
||
>4 5 éb br
|
||
>4 6 ébr ébr
|
||
>4 7 ébre nébr
|
||
>4 8 ébreu énébr
|
||
>4 9 ébreux ténébr
|
||
>b
|
||
>5 5 b b
|
||
>5 6 br éb
|
||
>5 7 bre néb
|
||
>5 8 breu énéb
|
||
>5 9 breux ténéb
|
||
>r
|
||
>6 6 r é
|
||
>6 7 re né
|
||
>6 8 reu éné
|
||
>6 9 reux téné
|
||
>e
|
||
>7 7 e n
|
||
>7 8 eu én
|
||
>7 9 eux tén
|
||
>u
|
||
>8 8 u é
|
||
>8 9 ux té
|
||
>x
|
||
>9 9 x t
|
||
|
||
s=é
|
||
print A${s[-2]}A B${s[-1]}B C${s[0]}C D${s[1]}D E${s[2]}E
|
||
0:Out of range subscripts with multibyte characters
|
||
>AA BéB CC DéD EE
|
||
|
||
print ${a[(i)é]} ${a[(I)é]} ${a[${a[(i)é]},${a[(I)é]}]}
|
||
0:Reverse indexing with multibyte characters
|
||
>2 4 éné
|
||
|
||
print ${a[(r)én,(r)éb]}
|
||
0:Subscript searching with multibyte characters
|
||
>énéb
|
||
|
||
print ${a[(rb:1:)é,-1]}
|
||
print ${a[(rb:2:)é,-1]}
|
||
print ${a[(rb:3:)é,-1]}
|
||
print ${a[(rb:4:)é,-1]}
|
||
print ${a[(rb:5:)é,-1]}
|
||
0:Subscript searching with initial offset
|
||
>énébreux
|
||
>énébreux
|
||
>ébreux
|
||
>ébreux
|
||
>
|
||
|
||
print ${a[(rn:1:)é,-1]}
|
||
print ${a[(rn:2:)é,-1]}
|
||
print ${a[(rn:3:)é,-1]}
|
||
0:Subscript searching with count
|
||
>énébreux
|
||
>ébreux
|
||
>
|
||
|
||
print ${a[(R)én,(R)éb]}
|
||
0:Backward subscript searching with multibyte characters
|
||
>énéb
|
||
|
||
# Starting offsets with (R) seem to be so strange as to be hardly
|
||
# worth testing.
|
||
|
||
setopt extendedglob
|
||
[[ $a = (#b)t(én)(éb)reux ]] || print "Failed to match." >&2
|
||
for i in {1..${#match}}; do
|
||
print $match[i] $mbegin[i] $mend[i] ${a[$mbegin[i],$mend[i]]}
|
||
done
|
||
0:Multibyte offsets in pattern tests
|
||
>én 2 3 én
|
||
>éb 4 5 éb
|
||
|
||
b=${(U)a}
|
||
print $b
|
||
print ${(L)b}
|
||
desdichado="Je suis le $a, le veuf, l'inconsolé"
|
||
print ${(C)desdichado}
|
||
lxiv="l'état c'est moi"
|
||
print ${(C)lxiv}
|
||
0:Case modification of multibyte strings
|
||
>TÉNÉBREUX
|
||
>ténébreux
|
||
>Je Suis Le Ténébreux, Le Veuf, L'Inconsolé
|
||
>L'État C'Est Moi
|
||
|
||
array=(ølaf ødd øpened án encyclopædia)
|
||
barray=(${(U)array})
|
||
print $barray
|
||
print ${(L)barray}
|
||
print ${(C)array}
|
||
print ${(C)barray}
|
||
0:Case modification of arrays with multibyte strings
|
||
>ØLAF ØDD ØPENED ÁN ENCYCLOPÆDIA
|
||
>ølaf ødd øpened án encyclopædia
|
||
>Ølaf Ødd Øpened Án Encyclopædia
|
||
>Ølaf Ødd Øpened Án Encyclopædia
|
||
|
||
print $(( ##¥ ))
|
||
pound=£
|
||
print $(( #pound ))
|
||
alpha=α
|
||
print $(( ##α )) $(( #alpha ))
|
||
0:Conversion to Unicode in mathematical expressions
|
||
>165
|
||
>163
|
||
>945 945
|
||
|
||
unsetopt posix_identifiers
|
||
expr='hähä=3 || exit 1; print $hähä'
|
||
eval $expr
|
||
setopt posix_identifiers
|
||
(eval $expr)
|
||
1:POSIX_IDENTIFIERS option
|
||
>3
|
||
?(eval):1: command not found: hähä=3
|
||
|
||
foo="Ølaf«Ødd«øpénëd«ån«àpple"
|
||
print -l ${(s.«.)foo}
|
||
ioh="Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος."
|
||
print -l ${=ioh}
|
||
print ${(w)#ioh}
|
||
0:Splitting with multibyte characters
|
||
>Ølaf
|
||
>Ødd
|
||
>øpénëd
|
||
>ån
|
||
>àpple
|
||
>Ἐν
|
||
>ἀρχῇ
|
||
>ἦν
|
||
>ὁ
|
||
>λόγος,
|
||
>καὶ
|
||
>ὁ
|
||
>λόγος
|
||
>ἦν
|
||
>πρὸς
|
||
>τὸν
|
||
>θεόν,
|
||
>καὶ
|
||
>θεὸς
|
||
>ἦν
|
||
>ὁ
|
||
>λόγος.
|
||
>17
|
||
|
||
read -d £ one
|
||
read -d £ two
|
||
print $one
|
||
print $two
|
||
0:read with multibyte delimiter
|
||
<first£second£
|
||
>first
|
||
>second
|
||
|
||
(IFS=«
|
||
read -d » -A array
|
||
print -l $array)
|
||
0:read -A with multibyte IFS
|
||
<dominus«illuminatio«mea»ignored
|
||
>dominus
|
||
>illuminatio
|
||
>mea
|
||
|
||
read -k2 -u0 twochars
|
||
print $twochars
|
||
0:read multibyte characters
|
||
<«»ignored
|
||
>«»
|
||
|
||
read -q -u0 mb
|
||
print $?
|
||
0:multibyte character makes read -q return false
|
||
<«
|
||
>1
|
||
|
||
# See if the system grokks first-century Greek...
|
||
ioh="Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος."
|
||
for (( i = 1; i <= ${#ioh}; i++ )); do
|
||
# FC3 doesn't recognise ῇ (U+1FC7: Greek small letter eta with
|
||
# perispomeni and ypogegrammeni, of course) as a lower case character.
|
||
if [[ $ioh[i] != [[:lower:]] && $i != 7 ]]; then
|
||
for tp in upper space punct invalid; do
|
||
if [[ $tp = invalid || $ioh[i] = [[:${tp}:]] ]]; then
|
||
print "$i: $tp"
|
||
break
|
||
fi
|
||
done
|
||
fi
|
||
done
|
||
0:isw* functions on non-ASCII wide characters
|
||
>1: upper
|
||
>3: space
|
||
>8: space
|
||
>11: space
|
||
>13: space
|
||
>19: punct
|
||
>20: space
|
||
>24: space
|
||
>26: space
|
||
>32: space
|
||
>35: space
|
||
>40: space
|
||
>44: space
|
||
>49: punct
|
||
>50: space
|
||
>54: space
|
||
>59: space
|
||
>62: space
|
||
>64: space
|
||
>70: punct
|
||
|
||
ioh="Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος"
|
||
print ${ioh#[[:alpha:]]##}
|
||
print ${ioh##[[:alpha:]]##}
|
||
print ${ioh%[[:alpha:]]##}
|
||
print ${ioh%%[[:alpha:]]##}
|
||
print ${(S)ioh#λ*ς}
|
||
print ${(S)ioh##λ*ς}
|
||
print ${(S)ioh%θ*ς}
|
||
print ${(S)ioh%%θ*ς}
|
||
0:Parameter #, ##, %, %% with multibyte characters
|
||
>ν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος
|
||
> ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος
|
||
>Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγο
|
||
>Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ
|
||
>Ἐν ἀρχῇ ἦν ὁ , καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος
|
||
>Ἐν ἀρχῇ ἦν ὁ
|
||
>Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ ἦν ὁ λόγος
|
||
>Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ
|
||
|
||
foo=(κατέβην χθὲς εἰς Πειραιᾶ)
|
||
print ${(l.3..¥.r.3..£.)foo}
|
||
print ${(l.4..¥.r.2..£.)foo}
|
||
print ${(l.5..¥.r.1..£.)foo}
|
||
print ${(l.4..¥..«.r.4..£..».)foo}
|
||
print ${(l.4..¥..Σωκράτης.r.4..£..Γλαύκωνος.)foo}
|
||
0:simultaneous left and right padding
|
||
>κατέβη ¥χθὲς£ ¥¥εἰς£ Πειραι
|
||
>¥κατέβ ¥¥χθὲς ¥¥¥εἰς ¥Πειρα
|
||
>¥¥κατέ ¥¥¥χθὲ ¥¥¥¥εἰ ¥¥Πειρ
|
||
>«κατέβην ¥«χθὲς»£ ¥¥«εἰς»£ «Πειραιᾶ
|
||
>ςκατέβην ηςχθὲςΓλ τηςεἰςΓλ ςΠειραιᾶ
|
||
# er... yeah, that looks right...
|
||
|
||
foo=picobarn
|
||
print ${foo:s£bar£rod£:s¥rod¥stick¥}
|
||
0:Delimiters in modifiers
|
||
>picostickn
|
||
|
||
# TODO: if we get paired multibyte bracket delimiters to work
|
||
# (as Emacs does, the smug so-and-so), the following should change.
|
||
foo=bar
|
||
print ${(r£5££X£)foo}
|
||
print ${(l«10««Y««HI«)foo}
|
||
0:Delimiters in parameter flags
|
||
>barXX
|
||
>YYYYYHIbar
|
||
|
||
printf "%4.3s\n" főobar
|
||
0:Multibyte characters in printf widths
|
||
> főo
|
||
|
||
# We ask for case-insensitive sorting here (and supply upper case
|
||
# characters) so that we exercise the logic in the shell that lowers the
|
||
# case of the string for case-insensitive sorting.
|
||
print -oi HÛH HÔH HÎH HÊH HÂH
|
||
(LC_ALL=C; print -oi HAH HUH HEH HÉH HÈH)
|
||
0:Multibyte characters in print sorting
|
||
>HÂH HÊH HÎH HÔH HÛH
|
||
>HAH HEH HUH HÈH HÉH
|
||
|
||
# These are control characters in Unicode, so don't show up.
|
||
# We just want to check they're not being treated as tokens.
|
||
for x in {128..150}; do
|
||
print ${(#)x}
|
||
done | while read line; do
|
||
print ${#line} $(( #line ))
|
||
done
|
||
0:evaluated character number with multibyte characters
|
||
>1 128
|
||
>1 129
|
||
>1 130
|
||
>1 131
|
||
>1 132
|
||
>1 133
|
||
>1 134
|
||
>1 135
|
||
>1 136
|
||
>1 137
|
||
>1 138
|
||
>1 139
|
||
>1 140
|
||
>1 141
|
||
>1 142
|
||
>1 143
|
||
>1 144
|
||
>1 145
|
||
>1 146
|
||
>1 147
|
||
>1 148
|
||
>1 149
|
||
>1 150
|
||
|
||
touch ngs1txt ngs2txt ngs10txt ngs20txt ngs100txt ngs200txt
|
||
setopt numericglobsort
|
||
print -l ngs*
|
||
0:NUMERIC_GLOB_SORT option in UTF-8 locale
|
||
>ngs1txt
|
||
>ngs2txt
|
||
>ngs10txt
|
||
>ngs20txt
|
||
>ngs100txt
|
||
>ngs200txt
|
||
|
||
# Not strictly multibyte, but gives us a well-defined locale for testing.
|
||
foo=$'X\xc0Y\x07Z\x7fT'
|
||
print -r ${(q)foo}
|
||
0:Backslash-quoting of unprintable/invalid characters uses $'...'
|
||
>X$'\300'Y$'\a'Z$'\177'T
|
||
|
||
# This also isn't strictly multibyte and is here to reduce the
|
||
# likelihood of a "cannot do character set conversion" error.
|
||
(print $'\u00e9') 2>&1 | read
|
||
if [[ $REPLY != é ]]; then
|
||
print "warning: your system can't do simple Unicode conversion." >&$ZTST_fd
|
||
print "Check you have a correctly installed iconv library." >&$ZTST_fd
|
||
# cheat
|
||
repeat 4 print OK
|
||
else
|
||
testfn() { (LC_ALL=C; print $'\u00e9') }
|
||
repeat 4 testfn 2>&1 | while read line; do
|
||
if [[ $line = *"character not in range"* ]]; then
|
||
print OK
|
||
elif [[ $line = "?" ]]; then
|
||
print OK
|
||
else
|
||
print Failed: no error message and no question mark
|
||
fi
|
||
done
|
||
fi
|
||
true
|
||
0:error handling in Unicode quoting
|
||
>OK
|
||
>OK
|
||
>OK
|
||
>OK
|
||
|
||
tmp1='glob/\(\)Ą/*'
|
||
[[ glob/'()Ą'/foo == $~tmp1 ]] && print "Matched against $tmp1"
|
||
tmp1='glob/\(\)Ā/*'
|
||
[[ glob/'()Ā'/bar == $~tmp1 ]] && print "Matched against $tmp1"
|
||
0:Backslashes and metafied characters in patterns
|
||
>Matched against glob/()Ą/*
|
||
>Matched against glob/()Ā/*
|
||
|
||
mkdir 梶浦由記 'Пётр Ильич Чайковский'
|
||
(cd 梶浦由記; print ${${(%):-%~}:t})
|
||
(cd 'Пётр Ильич Чайковский'; print ${${(%):-%~}:t})
|
||
0:Metafied characters in prompt expansion
|
||
>梶浦由記
|
||
>Пётр Ильич Чайковский
|
||
|
||
(
|
||
setopt nonomatch
|
||
tmp1=Ą
|
||
tmpA=(Ą 'Пётр Ильич Чайковский' 梶浦由記)
|
||
print ${tmp1} ${(%)tmp1} ${(%%)tmp1}
|
||
print ${#tmp1} ${#${(%)tmp1}} ${#${(%%)tmp1}}
|
||
print ${tmpA}
|
||
print ${(%)tmpA}
|
||
print ${(%%)tmpA}
|
||
)
|
||
0:More metafied characters in prompt expansion
|
||
>Ą Ą Ą
|
||
>1 1 1
|
||
>Ą Пётр Ильич Чайковский 梶浦由記
|
||
>Ą Пётр Ильич Чайковский 梶浦由記
|
||
>Ą Пётр Ильич Чайковский 梶浦由記
|
||
|
||
setopt cbases
|
||
print $'\xc5' | read
|
||
print $(( [#16] #REPLY ))
|
||
0:read passes through invalid multibyte characters
|
||
>0xC5
|
||
|
||
word=abcま
|
||
word[-1]=
|
||
print $word
|
||
word=abcま
|
||
word[-2]=
|
||
print $word
|
||
word=abcま
|
||
word[4]=d
|
||
print $word
|
||
word=abcま
|
||
word[3]=not_c
|
||
print $word
|
||
0:assignment with negative indices
|
||
>abc
|
||
>abま
|
||
>abcd
|
||
>abnot_cま
|