Điều này có thể được thực hiện hoàn toàn bên trong. Mặc dù thực hiện thao tác chuỗi trong một vòng lặp trong bash là chậm, có một thuật toán đơn giản là lôgarit trong số hoạt động của vỏ, vì vậy bash thuần túy là một lựa chọn khả thi ngay cả đối với các chuỗi dài.
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"
}
Hộp công cụ tiêu chuẩn bao gồm cmp
để so sánh tệp nhị phân. Theo mặc định, nó cho biết độ lệch byte của các byte khác nhau đầu tiên. Có một trường hợp đặc biệt khi một chuỗi là tiền tố của một chuỗi khác: cmp
tạo một thông báo khác trên STDERR; một cách dễ dàng để giải quyết vấn đề này là lấy chuỗi nào ngắn nhất.
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"
}
Lưu ý rằng cmp
hoạt động trên byte, nhưng thao tác chuỗi của bash hoạt động trên ký tự. Điều này tạo nên sự khác biệt về miền địa phương nhiều byte, ví dụ cho các miền địa phương bằng cách sử dụng bộ ký tự UTF-8. Hàm trên in ra tiền tố dài nhất của chuỗi byte. Để xử lý các chuỗi ký tự bằng phương thức này, trước tiên chúng ta có thể chuyển đổi các chuỗi thành mã hóa có độ rộng cố định. Giả sử bộ ký tự của miền địa phương là một tập con của Unicode, UTF-32 phù hợp với hóa đơn.
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"
}
ohh người đàn ông, thật tốt khi thấy rằng những người khác đấu tranh với điều này: D –
@ajreal: Chức năng được cung cấp khá dài và không hoạt động với khoảng trống trong chuỗi. Không ít câu hỏi của tôi là một bản sao. Xin lỗi vì chuyện đó. Sẽ đăng một bình luận ở đó –
Không trùng lặp: nhu cầu giao lộ không giống nhau. – jfg956