ทุบตีการขยายอาร์เรย์ว่างด้วย "set -u"


108

ฉันกำลังเขียนสคริปต์ bash ซึ่งมีset -uและฉันมีปัญหากับการขยายอาร์เรย์ที่ว่างเปล่า: bash ดูเหมือนจะถือว่าอาร์เรย์ว่างเป็นตัวแปรที่ไม่ได้ตั้งค่าระหว่างการขยาย:

$ set -u
$ arr=()
$ echo "foo: '${arr[@]}'"
bash: arr[@]: unbound variable

( declare -a arrไม่ช่วยเช่นกัน)

วิธีแก้ปัญหาทั่วไปสำหรับสิ่งนี้คือการใช้${arr[@]-}แทนดังนั้นการแทนที่สตริงว่างแทนที่จะเป็นอาร์เรย์ว่าง ("ไม่ได้กำหนด") อย่างไรก็ตามนี่ไม่ใช่วิธีแก้ปัญหาที่ดีเนื่องจากตอนนี้คุณไม่สามารถแยกแยะระหว่างอาร์เรย์ที่มีสตริงว่างเดียวกับอาร์เรย์ว่างได้ (@ - การขยายเป็นพิเศษในการทุบตีมันขยายออก"${arr[@]}"ไป"${arr[0]}" "${arr[1]}" …ซึ่งทำให้เป็นเครื่องมือที่สมบูรณ์แบบสำหรับการสร้างบรรทัดคำสั่ง)

$ countArgs() { echo $#; }
$ countArgs a b c
3
$ countArgs
0
$ countArgs ""
1
$ brr=("")
$ countArgs "${brr[@]}"
1
$ countArgs "${arr[@]-}"
1
$ countArgs "${arr[@]}"
bash: arr[@]: unbound variable
$ set +u
$ countArgs "${arr[@]}"
0

ดังนั้นมีวิธีแก้ปัญหานั้นไหมนอกเหนือจากการตรวจสอบความยาวของอาร์เรย์ในif(ดูตัวอย่างโค้ดด้านล่าง) หรือปิด-uการตั้งค่าสำหรับส่วนสั้น ๆ นั้น?

if [ "${#arr[@]}" = 0 ]; then
   veryLongCommandLine
else
   veryLongCommandLine "${arr[@]}"
fi

อัปเดต:bugsแท็กถูกลบเนื่องจากคำอธิบายของ ikegami

คำตอบ:


26

เพียงสำนวนที่ปลอดภัย${arr[@]+"${arr[@]}"}

นี่เป็นคำแนะนำในคำตอบของ ikegamiอยู่แล้ว แต่มีข้อมูลที่ผิดและการคาดเดามากมายในชุดข้อความนี้ รูปแบบอื่น ๆ เช่น${arr[@]-}หรือ${arr[@]:0}มีความไม่ปลอดภัยทั่วทั้งรุ่นใหญ่ของทุบตี

ดังตารางด้านล่างแสดงให้เห็นว่าส่วนขยายเดียวที่เชื่อถือได้ในเวอร์ชัน Bash ที่ทันสมัยทั้งหมดคือ${arr[@]+"${arr[@]}"}(คอลัมน์+") ข้อสังเกตการขยายอื่น ๆ อีกหลายรายการล้มเหลวใน Bash 4.2 รวมถึง (น่าเสียดาย) ${arr[@]:0}สำนวนที่สั้นกว่าซึ่งไม่เพียงให้ผลลัพธ์ที่ไม่ถูกต้อง แต่ล้มเหลวจริง หากคุณต้องการรองรับเวอร์ชันก่อน 4.4 และโดยเฉพาะอย่างยิ่ง 4.2 นี่เป็นสำนวนเดียวที่ใช้งานได้

ภาพหน้าจอของสำนวนต่างๆในเวอร์ชันต่างๆ

น่าเสียดายที่+การขยายอื่น ๆที่เมื่อมองอย่างรวดเร็วดูเหมือนว่าจะทำให้เกิดพฤติกรรมที่แตกต่างกันออกไป :+การขยายไม่ปลอดภัยเนื่องจาก:-expansionถือว่าอาร์เรย์ที่มีองค์ประกอบว่างเดียว ( ('')) เป็น "null" ดังนั้นจึงไม่ (สม่ำเสมอ) ขยายเป็นผลลัพธ์เดียวกัน

การอ้างถึงการขยายแบบเต็มแทนที่จะเป็นอาร์เรย์ที่ซ้อนกัน ( "${arr[@]+${arr[@]}}") ซึ่งฉันคาดว่าจะเทียบเท่าโดยประมาณนั้นไม่ปลอดภัยเช่นเดียวกันใน 4.2

คุณสามารถดูรหัสที่สร้างข้อมูลนี้พร้อมกับผลลัพธ์ของ bash เวอร์ชันเพิ่มเติมหลายรายการได้ในส่วนสำคัญนี้


1
"${arr[@]}"ฉันไม่เห็นคุณทดสอบ ฉันพลาดอะไรไปรึเปล่า? จากสิ่งที่ฉันเห็นมันใช้งานได้อย่างน้อยใน5.x.
x-yuri

1
@ x-yuri ใช่ Bash 4.4 แก้ไขสถานการณ์ คุณไม่จำเป็นต้องใช้รูปแบบนี้หากคุณรู้ว่าสคริปต์ของคุณจะทำงานบน 4.4+ เท่านั้น แต่หลายระบบยังคงใช้เวอร์ชันก่อนหน้านี้
dimo414

อย่างแน่นอน แม้จะดูดี (เช่นการจัดรูปแบบ) ช่องว่างพิเศษก็เป็นความชั่วร้ายของการทุบตีทำให้เกิดปัญหามากมาย
agg3l

บน bash 4.4.20 (1) สิ่งนี้ไม่ได้ผลตามที่ตั้งใจไว้ อ้างการขยายตัวของตัวแปรในคำตอบนี้ไม่ได้นับจำนวนของรายการในอาร์เรย์ แย่กว่านั้นมันจะปล่อยให้ตัวแปรไม่มีเครื่องหมาย
inetknght

@inetknght คุณสามารถแบ่งปันMCVEของสิ่งที่คุณกำลังสังเกตได้หรือไม่? แม้จะมีไวยากรณ์แปลก ๆ แต่ก็มีการอ้างถึงอย่างถูกต้อง ส่วนขยายด้านนอก (ไม่ได้ระบุคิวต์) จะขยายเป็นการขยายภายใน (อ้างถึง) เมื่ออาร์เรย์ไม่ว่างเปล่า
dimo414

85

ตามเอกสารประกอบ

ตัวแปรอาร์เรย์ถือเป็นชุดหากมีการกำหนดค่าตัวห้อย สตริงว่างเป็นค่าที่ถูกต้อง

ไม่มีการกำหนดค่าตัวห้อยดังนั้นจึงไม่ได้ตั้งค่าอาร์เรย์

แต่ในขณะที่เอกสารที่แสดงให้เห็นข้อผิดพลาดมีความเหมาะสมที่นี่นี้จะไม่มีอีกต่อไปกรณีตั้งแต่ 4.4

$ bash --version | head -n 1
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)

$ set -u

$ arr=()

$ echo "foo: '${arr[@]}'"
foo: ''

การใช้งาน: มีเงื่อนไขที่คุณสามารถใช้แบบอินไลน์เพื่อให้บรรลุสิ่งที่คุณต้องการในรุ่นเก่าเป็นแทน${arr[@]+"${arr[@]}"}"${arr[@]}"

$ function args { perl -E'say 0+@ARGV; say "$_: $ARGV[$_]" for 0..$#ARGV' -- "$@" ; }

$ set -u

$ arr=()

$ args "${arr[@]}"
-bash: arr[@]: unbound variable

$ args ${arr[@]+"${arr[@]}"}
0

$ arr=("")

$ args ${arr[@]+"${arr[@]}"}
1
0: 

$ arr=(a b c)

$ args ${arr[@]+"${arr[@]}"}
3
0: a
1: b
2: c

ทดสอบด้วย bash 4.2.25 และ 4.3.11


4
ใครสามารถอธิบายได้ว่าทำไมจึงได้ผล ฉันสับสนเกี่ยวกับสิ่งที่[@]+ทำได้จริงและเหตุใดวินาทีจึง${arr[@]}ไม่ทำให้เกิดข้อผิดพลาดที่ไม่ถูกผูกไว้
Martin von Wittich

3
${parameter+word}จะขยายเฉพาะwordเมื่อparameterไม่ได้ตั้งค่าไว้
ikegami

2
${arr+"${arr[@]}"}สั้นกว่าและดูเหมือนจะทำงานได้ดีเช่นกัน
Per Cederberg

3
@Per Cerderberg ไม่ทำงาน unset arr, arr[1]=a, args ${arr+"${arr[@]}"}VSargs ${arr[@]+"${arr[@]}"}
Ikegami

1
เพื่อความแม่นยำในกรณีที่การ+ขยายไม่เกิดขึ้น (กล่าวคืออาร์เรย์ว่าง) การขยายจะถูกแทนที่โดยไม่มีอะไรเลยซึ่งเป็นสิ่งที่อาร์เรย์ว่างขยายออกไป :+ไม่ปลอดภัยเนื่องจากยังถือว่า('')อาร์เรย์องค์ประกอบเดียวเป็น unset และในทำนองเดียวกันจะขยายเป็นอะไรเลยทำให้สูญเสียค่าไป
dimo414

24

คำตอบที่ยอมรับของ @ ikegami ผิดอย่างละเอียด! คาถาที่ถูกต้องคือ${arr[@]+"${arr[@]}"}:

$ countArgs () { echo "$#"; }
$ arr=('')
$ countArgs "${arr[@]:+${arr[@]}}"
0   # WRONG
$ countArgs ${arr[@]+"${arr[@]}"}
1   # RIGHT
$ arr=()
$ countArgs ${arr[@]+"${arr[@]}"}
0   # Let's make sure it still works for the other case...

ไม่สร้างความแตกต่างอีกต่อไป bash-4.4.23: arr=('') && countArgs "${arr[@]:+${arr[@]}}"ผลิต1. แต่${arr[@]+"${arr[@]}"}แบบฟอร์มอนุญาตให้แยกความแตกต่างระหว่างค่าว่าง / ไม่ว่างโดยการเพิ่ม / ไม่เพิ่มโคลอน
x-yuri

arr=('') && countArgs ${arr[@]:+"${arr[@]}"}-> 0, arr=('') && countArgs ${arr[@]+"${arr[@]}"}-> 1.
x-yuri

1
คำตอบของฉันได้รับการแก้ไขเมื่อนานมาแล้ว (อันที่จริงฉันแน่ใจว่าฉันเคยแสดงความคิดเห็นเกี่ยวกับคำตอบนี้ไว้ก่อนหน้านี้แล้ว!)
ikegami

16

ปรากฎว่ามีการเปลี่ยนแปลงการจัดการอาร์เรย์ในการเปิดตัวเมื่อเร็ว ๆ นี้ (2016/09/16) bash 4.4 (มีให้ใน Debian stretch เป็นต้น)

$ bash --version | head -n1
bash --version | head -n1
GNU bash, version 4.4.0(1)-release (x86_64-pc-linux-gnu)

ตอนนี้การขยายอาร์เรย์ว่างเปล่าไม่ส่งเสียงเตือน

$ set -u
$ arr=()
$ echo "${arr[@]}"

$ # everything is fine

ฉันสามารถยืนยันได้bash-4.4.12 "${arr[@]}"ก็เพียงพอแล้ว
x-yuri

14

นี่อาจเป็นอีกทางเลือกหนึ่งสำหรับผู้ที่ไม่ต้องการทำซ้ำ arr [@] และสามารถใช้สตริงว่างได้

echo "foo: '${arr[@]:-}'"

ทดสอบ:

set -u
arr=()
echo a "${arr[@]:-}" b # note two spaces between a and b
for f in a "${arr[@]:-}" b; do echo $f; done # note blank line between a and b
arr=(1 2)
echo a "${arr[@]:-}" b
for f in a "${arr[@]:-}" b; do echo $f; done

10
สิ่งนี้จะใช้ได้ผลถ้าคุณกำลังแก้ไขตัวแปร แต่ถ้าคุณต้องการใช้อาร์เรย์ในสิ่งforนี้จะจบลงด้วยสตริงว่างเดียวเมื่ออาร์เรย์ไม่ได้กำหนด / กำหนดเป็นว่างโดยที่คุณอาจต้องการให้ลูป body เพื่อไม่ทำงานหากไม่ได้กำหนดอาร์เรย์
Ash Berlin-Taylor

ขอบคุณ @AshBerlin ฉันเพิ่มห่วงสำหรับคำตอบของฉันเพื่อให้ผู้อ่านรับทราบ
Jayen

-1 สำหรับแนวทางนี้มันไม่ถูกต้อง สิ่งนี้จะแทนที่อาร์เรย์ว่างด้วยสตริงว่างเดียวซึ่งไม่เหมือนกัน รูปแบบที่แนะนำในคำตอบที่ยอมรับจะ${arr[@]+"${arr[@]}"}รักษาสถานะอาร์เรย์ว่างไว้อย่างถูกต้อง
dimo414

ดูคำตอบของฉันที่แสดงสถานการณ์ที่ส่วนขยายนี้หยุดทำงาน
dimo414

มันไม่ถูกต้อง มันบอกอย่างชัดเจนว่าจะให้สตริงว่างและยังมีอีกสองตัวอย่างที่คุณจะเห็นสตริงว่าง
Jayen

7

คำตอบของ @ ikegami ถูกต้อง แต่ฉันคิดว่าไวยากรณ์${arr[@]+"${arr[@]}"}น่ากลัว หากคุณใช้ชื่อตัวแปรอาร์เรย์แบบยาวมันจะเริ่มดู spaghetti-ish เร็วกว่าปกติ

ลองสิ่งนี้แทน:

$ set -u

$ count() { echo $# ; } ; count x y z
3

$ count() { echo $# ; } ; arr=() ; count "${arr[@]}"
-bash: abc[@]: unbound variable

$ count() { echo $# ; } ; arr=() ; count "${arr[@]:0}"
0

$ count() { echo $# ; } ; arr=(x y z) ; count "${arr[@]:0}"
3

ดูเหมือนว่าตัวดำเนินการ Bash array slice จะให้อภัยมาก

แล้วทำไม Bash ถึงจัดการเคสขอบของอาร์เรย์ได้ยากขนาดนี้? เฮ้อ. ฉันไม่สามารถรับประกันได้ว่าเวอร์ชันของคุณจะอนุญาตให้ใช้ตัวดำเนินการส่วนอาร์เรย์ในทางที่ผิด แต่มันก็ใช้งานได้ดีสำหรับฉัน

ข้อแม้: ฉันใช้GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu) ไมล์สะสมของคุณอาจแตกต่างกันไป


9
เดิม ikegami มีสิ่งนี้ แต่ลบออกเพราะไม่น่าเชื่อถือทั้งในทางทฤษฎี (ไม่มีเหตุผลว่าทำไมจึงควรใช้งานได้) และในทางปฏิบัติ (bash รุ่นของ OP ไม่ยอมรับ)

@hvd: ขอบคุณสำหรับการอัปเดต ผู้อ่าน: โปรดเพิ่มความคิดเห็นหากคุณพบเวอร์ชันของ bash ที่รหัสด้านบนใช้ไม่ได้
kevinarpe

hvp ทำไปแล้วและฉันจะบอกคุณด้วย: "${arr[@]:0}"ให้-bash: arr[@]: unbound variable.
ikegami

สิ่งหนึ่งที่ควรทำงานข้ามเวอร์ชันคือการตั้งค่าอาร์เรย์เริ่มต้นarr=("_dummy_")และใช้การขยาย${arr[@]:1}ทุกที่ สิ่งนี้ถูกกล่าวถึงในคำตอบอื่น ๆ โดยอ้างถึงค่า Sentinel
init_js

1
@init_js: การแก้ไขของคุณถูกปฏิเสธอย่างน่าเศร้า ฉันขอแนะนำให้คุณเพิ่มเป็นคำตอบแยกต่างหาก (Ref: stackoverflow.com/review/suggested-edits/19027379 )
kevinarpe

6

ความไม่ลงรอยกัน "น่าสนใจ" แน่นอน

นอกจากนี้

$ set -u
$ echo $#
0
$ echo "$1"
bash: $1: unbound variable   # makes sense (I didn't set any)
$ echo "$@" | cat -e
$                            # blank line, no error

แม้ว่าฉันจะยอมรับว่าพฤติกรรมในปัจจุบันอาจไม่ใช่ข้อบกพร่องตามที่ @ikegami อธิบาย แต่ IMO เราสามารถพูดได้ว่าจุดบกพร่องนั้นอยู่ในคำจำกัดความ (ของ "set") เองและ / หรือความจริงที่ว่ามันถูกนำไปใช้อย่างไม่สอดคล้องกัน ย่อหน้าก่อนหน้าในหน้าคนพูดว่า

... ${name[@]}ขยายแต่ละองค์ประกอบของชื่อเป็นคำแยกกัน เมื่อไม่มีสมาชิกอาร์เรย์ให้${name[@]}ขยายเป็นอะไรเลย

ซึ่งสอดคล้องอย่างสิ้นเชิงกับสิ่งที่กล่าวเกี่ยวกับการขยายพารามิเตอร์ตำแหน่งใน"$@". ไม่ใช่ว่าไม่มีความไม่สอดคล้องกันอื่น ๆ ในพฤติกรรมของอาร์เรย์และพารามิเตอร์ตำแหน่ง ... แต่สำหรับฉันแล้วไม่มีคำใบ้ว่ารายละเอียดนี้ควรไม่สอดคล้องกันระหว่างทั้งสอง

ดำเนินการต่อ

$ arr=()
$ echo "${arr[@]}"
bash: arr[@]: unbound variable   # as we've observed.  BUT...
$ echo "${#arr[@]}"
0                                # no error
$ echo "${!arr[@]}" | cat -e
$                                # no error

ดังนั้นarr[]ไม่ได้เป็นเช่นนั้นไม่ได้ผูกไว้ว่าเราไม่สามารถได้รับการนับจำนวนขององค์ประกอบของมัน (0) หรือ (ว่าง) รายการคีย์ของมันหรือไม่? สำหรับฉันสิ่งเหล่านี้สมเหตุสมผลและมีประโยชน์ - สิ่งเดียวที่ดูเหมือนจะเป็นการขยาย${arr[@]}(และ${arr[*]})


2

ฉันกำลังเสริมคำตอบของ@ ikegami (ยอมรับ) และ@ kevinarpe (ก็ดีด้วย)

คุณสามารถ"${arr[@]:+${arr[@]}}"แก้ไขปัญหาได้ ด้านขวามือ (เช่นหลัง:+) จัดเตรียมนิพจน์ที่จะใช้ในกรณีที่ไม่ได้กำหนดด้านซ้ายมือ / null

ไวยากรณ์เป็นอาร์เคน โปรดทราบว่าทางด้านขวามือของนิพจน์จะมีการขยายพารามิเตอร์ดังนั้นควรให้ความสนใจเป็นพิเศษกับการอ้างถึงที่สอดคล้องกัน

: example copy arr into arr_copy
arr=( "1 2" "3" )
arr_copy=( "${arr[@]:+${arr[@]}}" ) # good. same quoting. 
                                    # preserves spaces

arr_copy=( ${arr[@]:+"${arr[@]}"} ) # bad. quoting only on RHS.
                                    # copy will have ["1","2","3"],
                                    # instead of ["1 2", "3"]

เช่นเดียวกับที่ @kevinarpe กล่าวถึงไวยากรณ์ arcane ที่น้อยกว่าคือการใช้สัญกรณ์อาร์เรย์สไลซ์${arr[@]:0}(ในเวอร์ชัน Bash >= 4.4) ซึ่งขยายไปยังพารามิเตอร์ทั้งหมดโดยเริ่มจากดัชนี 0 นอกจากนี้ยังไม่ต้องการการทำซ้ำมากนัก ส่วนขยายนี้ใช้งานได้โดยไม่คำนึงถึงset -uดังนั้นคุณสามารถใช้สิ่งนี้ได้ตลอดเวลา หน้าคนพูดว่า (ภายใต้การขยายพารามิเตอร์ ):

  • ${parameter:offset}

  • ${parameter:offset:length}

    ... ถ้าพารามิเตอร์เป็นชื่ออาร์เรย์จัดทำดัชนี subscripted โดย@หรือผลที่ได้เป็นสมาชิกระยะเวลาของการเริ่มต้นกับอาร์เรย์* ${parameter[offset]}ค่าชดเชยเชิงลบถูกนำมาเทียบกับค่าหนึ่งที่มากกว่าดัชนีสูงสุดของอาร์เรย์ที่ระบุ เป็นข้อผิดพลาดในการขยายหากความยาวประเมินเป็นตัวเลขที่น้อยกว่าศูนย์

นี่คือตัวอย่างที่จัดทำโดย @kevinarpe โดยมีการจัดรูปแบบอื่นเพื่อวางเอาต์พุตในหลักฐาน:

set -u
function count() { echo $# ; };
(
    count x y z
)
: prints "3"

(
    arr=()
    count "${arr[@]}"
)
: prints "-bash: arr[@]: unbound variable"

(
    arr=()
    count "${arr[@]:0}"
)
: prints "0"

(
    arr=(x y z)
    count "${arr[@]:0}"
)
: prints "3"

ลักษณะการทำงานนี้แตกต่างกันไปตามเวอร์ชันของ Bash คุณอาจสังเกตเห็นว่าตัวดำเนินการความยาว${#arr[@]}จะประเมินเป็น0อาร์เรย์ว่างเสมอโดยไม่คำนึงถึงset -uโดยไม่ก่อให้เกิด 'ข้อผิดพลาดของตัวแปรที่ไม่ถูกผูกไว้'


น่าเสียดายที่:0สำนวนล้มเหลวใน Bash 4.2 ดังนั้นนี่จึงไม่ใช่แนวทางที่ปลอดภัย ดูคำตอบของฉัน
dimo414

1

ต่อไปนี้เป็นสองวิธีในการทำสิ่งนี้วิธีหนึ่งโดยใช้ทหารรักษาการณ์และอีกวิธีหนึ่งโดยใช้เงื่อนไขต่อท้าย:

#!/bin/bash
set -o nounset -o errexit -o pipefail
countArgs () { echo "$#"; }

arrA=( sentinel )
arrB=( sentinel "{1..5}" "./*" "with spaces" )
arrC=( sentinel '$PWD' )
cmnd=( countArgs "${arrA[@]:1}" "${arrB[@]:1}" "${arrC[@]:1}" )
echo "${cmnd[@]}"
"${cmnd[@]}"

arrA=( )
arrB=( "{1..5}" "./*"  "with spaces" )
arrC=( '$PWD' )
cmnd=( countArgs )
# Checks expansion of indices.
[[ ! ${!arrA[@]} ]] || cmnd+=( "${arrA[@]}" )
[[ ! ${!arrB[@]} ]] || cmnd+=( "${arrB[@]}" )
[[ ! ${!arrC[@]} ]] || cmnd+=( "${arrC[@]}" )
echo "${cmnd[@]}"
"${cmnd[@]}"

0

ความไม่สอดคล้องที่น่าสนใจ; สิ่งนี้ช่วยให้คุณสามารถกำหนดสิ่งที่ "ไม่ถือว่าเป็นชุด" แต่ยังปรากฏในผลลัพธ์ของdeclare -p

arr=()
set -o nounset
echo ${arr[@]}
 =>  -bash: arr[@]: unbound variable
declare -p arr
 =>  declare -a arr='()'

อัปเดต: ตามที่คนอื่นกล่าวถึงแก้ไขใน 4.4 ที่เผยแพร่หลังจากโพสต์คำตอบนี้


นั่นเป็นเพียงไวยากรณ์ของอาร์เรย์ที่ไม่ถูกต้อง คุณต้องการecho ${arr[@]}(แต่ก่อน Bash 4.4 คุณจะยังคงเห็นข้อผิดพลาด)
dimo414

ขอบคุณ @ dimo414 ครั้งต่อไปแนะนำให้แก้ไขแทนการลงคะแนน BTW หากคุณได้ลองecho $arr[@]ด้วยตัวเองคุณจะเห็นว่าข้อความแสดงข้อผิดพลาดนั้นแตกต่างกัน
MarcH

-2

วิธีที่ง่ายที่สุดและเข้ากันได้น่าจะเป็น:

$ set -u
$ arr=()
$ echo "foo: '${arr[@]-}'"

1
OP เองแสดงให้เห็นว่าสิ่งนี้ไม่ได้ผล มันขยายเป็นสตริงว่างแทนที่จะไม่มีอะไรเลย
ikegami

ถูกต้องดังนั้นจึงใช้ได้สำหรับการแก้ไขสตริง แต่ไม่วนซ้ำ
Craig Ringer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.