यह पूरी तरह से बैश के अंदर किया जा सकता है। हालांकि बैश में एक लूप में स्ट्रिंग हेरफेर करना धीमा है, एक सरल एल्गोरिथ्म है जो शेल ऑपरेशन की संख्या में लॉगरिदमिक है, इसलिए लंबे स्ट्रिंग्स के लिए भी शुद्ध बैश एक व्यवहार्य विकल्प है।
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
बाइट्स पर काम होता है, लेकिन बैश का स्ट्रिंग हेरफेर पात्रों पर संचालित होता है। यह यूटीएफ -8 वर्ण सेट का उपयोग करने वाले उदाहरण स्थानों के लिए, मल्टीबाइट स्थानों में अंतर करता है। ऊपर का कार्य बाइट स्ट्रिंग के सबसे लंबे उपसर्ग को प्रिंट करता है। इस विधि के साथ वर्ण स्ट्रिंग्स को संभालने के लिए, हम पहले स्ट्रिंग्स को निश्चित-चौड़ाई एन्कोडिंग में परिवर्तित कर सकते हैं। लोकेल के कैरेक्टर सेट को यूनिकोड का उपसमूह मानकर, 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"
}