두 줄이 있습니다. 예제를 위해 다음과 같이 설정되었습니다.
string1="test toast"
string2="test test"
내가 원하는 것은 문자열의 시작 부분에서 겹치는 부분을 찾는 것입니다. 겹침으로 위의 예제에서 문자열 “test t”를 의미합니다.
# I look for the command
command "$string1" "$string2"
# that outputs:
"test t"
문자열이 string1="atest toast"; string2="test test"
검사를 시작한 후 시작 부분부터 시작하여 “a”이후에 겹치지 않습니다 string1
.
답변
추가 할 오류 검사와 함께 이와 같은 기능을 생각할 수 있습니다.
common_prefix() {
local n=0
while [[ "${1:n:1}" == "${2:n:1}" ]]; do
((n++))
done
echo "${1:0:n}"
}
답변
이것은 bash 내부에서 완전히 수행 할 수 있습니다. bash의 루프에서 문자열 조작을 수행하는 것은 느리지 만 셸 작업 수에 로그가 간단한 알고리즘이 있으므로 순수한 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
바이트에서 작동하지만 배쉬의 문자열 조작 문자에서 작동합니다. 따라서 UTF-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"
}
답변
sed에서 문자열에 줄 바꿈 문자가 없다고 가정하면 :
string1="test toast"
string2="test test"
printf "%s\n" "$string1" "$string2" | sed -e 'N;s/^\(.*\).*\n\1.*$/\1/'
답변
이것은 나에게 조잡한 것처럼 보이지만 무차별 대항을 통해 할 수 있습니다.
#!/bin/bash
string1="test toast"
string2="test test"
L=1 # Prefix length
while [[ ${string1:0:$L} == ${string2:0:$L} ]]
do
((L = L + 1))
done
echo Overlap: ${string1:0:$((L - 1))}
나는 영리한 알고리즘이 존재하기를 원하지만 짧은 검색으로는 찾을 수 없습니다.