Dies kann vollständig innerhalb von Bash erfolgen. Obwohl die Manipulation von Zeichenfolgen in einer Schleife in Bash langsam ist, gibt es einen einfachen Algorithmus, der in Bezug auf die Anzahl der Shell-Operationen logarithmisch ist. Daher ist reine Bash auch für lange Zeichenfolgen eine praktikable Option.
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"
}
Die Standard-Toolbox enthält cmp
den Vergleich von Binärdateien. Standardmäßig gibt es den Byte-Offset der ersten unterschiedlichen Bytes an. Es gibt einen Sonderfall, wenn eine Zeichenfolge ein Präfix der anderen ist: cmp
Erzeugt eine andere Nachricht auf STDERR; Eine einfache Möglichkeit, damit umzugehen, besteht darin, die kürzeste Zeichenfolge zu verwenden.
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"
}
Beachten Sie, dass dies cmp
mit Bytes funktioniert, die String-Manipulation von bash jedoch mit Zeichen. Dies macht einen Unterschied bei Multibyte-Gebietsschemas, beispielsweise bei Gebietsschemas, die den UTF-8-Zeichensatz verwenden. Die obige Funktion gibt das längste Präfix einer Byte-Zeichenfolge aus. Um Zeichenfolgen mit dieser Methode zu verarbeiten, können wir die Zeichenfolgen zunächst in eine Codierung mit fester Breite konvertieren. Angenommen, der Zeichensatz des Gebietsschemas ist eine Teilmenge von Unicode, passt UTF-32 in die Rechnung.
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"
}