Ini bisa dilakukan sepenuhnya di dalam bash. Meskipun melakukan manipulasi string dalam satu loop dalam bash lambat, ada algoritma sederhana yang logaritmik dalam jumlah operasi shell, jadi bash murni adalah pilihan yang layak bahkan untuk string panjang.
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"
}
Kotak alat standar termasuk cmp
untuk membandingkan file biner. Secara default, ini menunjukkan offset byte dari byte pertama yang berbeda. Ada kasus khusus ketika satu string adalah awalan dari yang lain: cmp
menghasilkan pesan berbeda pada STDERR; cara mudah untuk mengatasinya adalah dengan mengambil string mana yang paling pendek.
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"
}
Catatan yang cmp
beroperasi pada byte, tetapi manipulasi string bash beroperasi pada karakter. Ini membuat perbedaan dalam lokal multibyte, untuk contoh lokal menggunakan set karakter UTF-8. Fungsi di atas mencetak awalan terpanjang dari string byte. Untuk menangani string karakter dengan metode ini, pertama-tama kita dapat mengkonversi string ke encoding dengan lebar tetap. Dengan asumsi set karakter lokal adalah bagian dari Unicode, UTF-32 sesuai dengan tagihan.
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"
}