ซึ่งสามารถทำได้ทั้งหมดภายในทุบตี แม้ว่าการจัดการกับสตริงในลูปใน bash จะช้า แต่มีอัลกอริธึมง่ายๆที่เป็นลอการิทึมในจำนวนการทำงานของเชลล์ดังนั้นการทุบตีบริสุทธิ์จึงเป็นตัวเลือกที่ทำงานได้แม้จะเป็นสตริงที่ยาว
longest_common_prefix () {
local prefix= n
## Truncate the two strings to the minimum of their lengths
if [[ ${#1} -gt ${#2} ]]; then
set -- "${1:0:${#2}}" "$2"
else
set -- "$1" "${2:0:${#1}}"
fi
## Binary search for the first differing character, accumulating the common prefix
while [[ ${#1} -gt 1 ]]; do
n=$(((${#1}+1)/2))
if [[ ${1:0:$n} == ${2:0:$n} ]]; then
prefix=$prefix${1:0:$n}
set -- "${1:$n}" "${2:$n}"
else
set -- "${1:0:$n}" "${2:0:$n}"
fi
done
## Add the one remaining character, if common
if [[ $1 = $2 ]]; then prefix=$prefix$1; fi
printf %s "$prefix"
}
กล่องเครื่องมือมาตรฐานรวมถึงcmp
การเปรียบเทียบไฟล์ไบนารี โดยค่าเริ่มต้นมันบ่งบอกถึงการชดเชยไบต์ของไบต์ที่แตกต่างกันครั้งแรก มีกรณีพิเศษเมื่อหนึ่งสตริงเป็นคำนำหน้าของอื่น ๆ : cmp
สร้างข้อความที่แตกต่างใน STDERR; วิธีง่ายๆในการจัดการกับสิ่งนี้คือการใช้สตริงใดก็ตามที่สั้นที่สุด
longest_common_prefix () {
local LC_ALL=C offset prefix
offset=$(export LC_ALL; cmp <(printf %s "$1") <(printf %s "$2") 2>/dev/null)
if [[ -n $offset ]]; then
offset=${offset%,*}; offset=${offset##* }
prefix=${1:0:$((offset-1))}
else
if [[ ${#1} -lt ${#2} ]]; then
prefix=$1
else
prefix=$2
fi
fi
printf %s "$prefix"
}
โปรดทราบว่าcmp
ทำงานเป็นไบต์ แต่การจัดการสตริงของ bash ดำเนินการกับอักขระ สิ่งนี้สร้างความแตกต่างในโลแคลหลายไบต์สำหรับตัวอย่างโลแคลที่ใช้ชุดอักขระ UTF-8 ฟังก์ชั่นด้านบนพิมพ์คำนำหน้าที่ยาวที่สุดของสตริงไบต์ เพื่อจัดการสตริงอักขระด้วยวิธีนี้เราสามารถแปลงสตริงเป็นการเข้ารหัสความกว้างคงที่ สมมติว่าชุดอักขระของโลแคลเป็นชุดย่อยของ Unicode, UTF-32 เหมาะกับการเรียกเก็บเงิน
longest_common_prefix () {
local offset prefix LC_CTYPE="${LC_ALL:=$LC_CTYPE}"
offset=$(unset LC_ALL; LC_MESSAGES=C cmp <(printf %s "$1" | iconv -t UTF-32) \
<(printf %s "$2" | iconv -t UTF-32) 2>/dev/null)
if [[ -n $offset ]]; then
offset=${offset%,*}; offset=${offset##* }
prefix=${1:0:$((offset/4-1))}
else
if [[ ${#1} -lt ${#2} ]]; then
prefix=$1
else
prefix=$2
fi
fi
printf %s "$prefix"
}