Bash中的Java String.hashCode()实现

Bash中的Java String.hashCode()实现,bash,Bash,我正在尝试在Bash中使用IMLPElement String.hashCode()函数。我想不出那只虫子 这是我的示例实现 function hashCode(){ #similar function to java String.hashCode() foo=$1 echo $foo h=0 for (( i=0; i<${#foo}; i++ )); do val=$(ord ${foo:$i:1}) echo $val if ((31 * h + val &

我正在尝试在Bash中使用IMLPElement String.hashCode()函数。我想不出那只虫子

这是我的示例实现

function hashCode(){ #similar function to java String.hashCode()
foo=$1
echo $foo
h=0
for (( i=0; i<${#foo}; i++ )); do
    val=$(ord ${foo:$i:1})
    echo $val
    if ((31 * h + val > 2147483647)) 
    then
        h=$((-2147483648 + (31 * h + val) % 2147483648 ))

    elif ((31 * h + val < -2147483648))
    then
        h=$(( 2147483648 - ( 31 * h + val) % 2147483648 )) 
    else
        h=$(( 31 * h + val))
    fi
done
printf %d $h
}

function ord() { #asci to int conversion
    LC_CTYPE=C printf %d "'$1"
}
function hashCode(){#类似于java String.hashCode()的函数
foo=$1
回声$foo
h=0
对于((i=0;i 2147483647))
然后
h=$(-2147483648+(31*h+val)%2147483648))
elif((31*h+val<-2147483648))
然后
h=$((2147483648-(31*h+val)%2147483648))
其他的
h=$((31*h+val))
fi
完成
printf%d$h
}
函数ord(){#asci到int的转换
LC_CTYPE=C printf%d“$1”
}
Java函数如下所示

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}
public int hashCode(){
int h=散列;
如果(h==0&&value.length>0){
char val[]=值;
for(int i=0;i
字符串“\uuu索引\u暂存\u数据\uu 0\u 1230ee6d-c37a-46cf-821c-55412f543fa6”的预期输出为“1668783629”,但输出为-148458597


注意-必须处理java int溢出和下溢。

Vinujan,您的代码是为了使用所包含的算法对给定字符串进行哈希运算。您不需要
ord
函数,因为您可以使用
printf-v val“%d”'${foo:$i:1}“
(除非您需要
LC\u CTYPE=C
来实现字符集差异)将文字转换为ASCII值

例如,只需对代码稍作调整,它就可以正确地散列字符串“hello”:

#!/bin/bash

function hashCode() {
    local foo="$1"
    local -i h=0
    for ((i = 0; i < ${#foo}; i++)); do

        printf -v val "%d" "'${foo:$i:1}"  # val is ASCII val

        if ((31 * h + val > 2147483647))   # hash scheme
        then
            h=$((-2147483648 + (31 * h + val) % 2147483648 ))
        elif ((31 * h + val < -2147483648))
        then
            h=$(( 2147483648 - ( 31 * h + val) % 2147483648 )) 
        else
            h=$(( 31 * h + val))
        fi
    done
    printf "%d" $h    # final hashCode in decimal
}

hash=$(hashCode "$1")

printf "\nhashCode: 0x%02x (%d decimal)\n" $hash $hash
看起来有问题的地方是散列算法本身。例如,较长的字符串(如
password
)将导致您的方案返回一个看起来可疑的负64位值,例如:

$ bash hashcode.sh password

hashCode: 0xffffffffb776462d (-1216985555 decimal)
这可能是你想要的散列,我没有什么可以比较的算法。仔细检查,如果仍然有问题,请编辑您的问题,并准确描述在运行脚本并将输出添加到问题中时遇到的问题/错误/等


编辑哈希函数以获得更好的行为

如果没有要实现的算法,我唯一能做的就是重新格式化您提供的算法,以便在计算超过
INT\u MAX/INT\u MIN
时表现更好。看看您现有的算法,它似乎使问题变得更糟,因为遇到了大量数据,而不是平滑值以确保它们保持在边界内

坦率地说,当值超过/低于这些限制时,在减少模2147483648的值之前,您似乎忽略了减去
INT\u MIN
或将
INT\u MAX
添加到
h
。(例如,您忘记了减法和加法周围的括号)简单地将其添加到哈希算法似乎可以产生更好的行为和所需的输出

我还将散列计算的结果保存在
hval
中,这样它就不会在每个循环中计算多次,例如

function hashCode() {
    local foo="$1"
    local -i h=0
    for ((i = 0; i < ${#foo}; i++)); do

        printf -v val "%d" "'${foo:$i:1}"  # val is ASCII val

        hval=$((31 * h + val))

        if ((hval > 2147483647))   # hash scheme
        then
            h=$(( (hval - 2147483648) % 2147483648 ))
        elif ((hval < -2147483648))
        then
            h=$(( (hval + 2147483648) % 2147483648 ))
        else
            h=$(( hval ))
        fi
    done
    printf "%d" $h    # final hashCode in decimal
}
请注意,它确实会产生您的预期输出:

$ bash hashcode2.sh "__INDEX_STAGING_DATA__0_1230ee6d-c37a-46cf-821c-55412f543fa6"

hashCode: 0x63779e0d (1668783629 decimal)

让我知道这是否是您试图做的事情。

我得到了一个精益解决方案:

hashCode() {
    o=$1
    h=0
    for j in $(seq 1 ${#o})
    do
        a=$((j-1))
        c=${o:$a:1}
        v=$(echo -n "$c" | od -d)
        i=${v:10:3}
        h=$((31 * $h + $i ))
        # echo -n a $a c $c i $i h $h
        h=$(( (2**31-1) & $h ))
        # echo -e "\t"$h
    done
    echo $h
}
哪个是错的错误是在我对
(2**31-1)^$h的巧妙按位ORing中,按位ANDing似乎更明智一些:
(2**31-1)和$h

这可以概括为:

hashCode() {
    o=$1
    h=0
    for j in $(seq 1 ${#o})
    do
        v=$(echo -n "${$o:$((j-1)):1}" | od -d)
        h=$(( (31 * $h + ${v:10:3}) & (2**31-1) ))
    done
    echo $h
}

val=$(ord${foo:$i:1})
中的
ord
是什么?我忘了放那个函数,它正在将字符转换为ascii值。现在编辑用
inth=hash初始化h-什么是哈希?什么是价值?字符串toCharArray()?嗨,大卫·C·兰金,谢谢你的贡献。我已经添加了我的预期输出和当前输出。好吧,这更有意义,所以问题在于您对实际哈希算法的解释。从
INT\u MAX
INT\u MIN
的一些摆动,等等。。看起来他们的签名方式可能有问题。明天我会有一点时间来研究它,希望我们能帮你解决。谢谢大卫的解决方案。我就快到了。再次感谢。帮了大忙。是的,你是。非常接近。那只不过是树林中的一棵你可以盯着看几天的树。在这种情况下,两只眼睛总比一只好。谢谢@user unknown。这个看起来很短D
hashCode() {
    o=$1
    h=0
    for j in $(seq 1 ${#o})
    do
        a=$((j-1))
        c=${o:$a:1}
        v=$(echo -n "$c" | od -d)
        i=${v:10:3}
        h=$((31 * $h + $i ))
        # echo -n a $a c $c i $i h $h
        h=$(( (2**31-1) & $h ))
        # echo -e "\t"$h
    done
    echo $h
}
hashCode() {
    o=$1
    h=0
    for j in $(seq 1 ${#o})
    do
        v=$(echo -n "${$o:$((j-1)):1}" | od -d)
        h=$(( (31 * $h + ${v:10:3}) & (2**31-1) ))
    done
    echo $h
}