将UTF-8字符编码函数从PHP转换为Java
我正在尝试将一个PHP编码函数转换为Android Java方法。因为Java字符串长度函数处理UTF-8字符串的方式不同。在转换第二个UTF-8STR2时,我未能使翻译后的Java代码与PHP代码一致。第一个非UTF-8字符串不起作用 原始PHP代码是:将UTF-8字符编码函数从PHP转换为Java,java,string,utf-8,character-encoding,Java,String,Utf 8,Character Encoding,我正在尝试将一个PHP编码函数转换为Android Java方法。因为Java字符串长度函数处理UTF-8字符串的方式不同。在转换第二个UTF-8STR2时,我未能使翻译后的Java代码与PHP代码一致。第一个非UTF-8字符串不起作用 原始PHP代码是: function myhash_php($string,$key) { $strLen = strlen($string); $keyLen = strlen($key); $j=0 ; $hash = "
function myhash_php($string,$key) {
$strLen = strlen($string);
$keyLen = strlen($key);
$j=0 ; $hash = "" ;
for ($i = 0; $i < $strLen; $i++) {
$ordStr = ord(substr($string,$i,1));
if ($j == $keyLen) { $j = 0; }
$ordKey = ord(substr($key,$j,1));
$j++;
$hash .= strrev(base_convert(dechex($ordStr + $ordKey),16,36));
}
return $hash;
}
$str1 = "good friend" ;
$str2 = "好友" ; // strlen($str2) == 6
$key = "iuyhjf476" ;
echo "php encode str1 '". $str1 ."'=".myhash_php($str1, $key)."<br>";
echo "php encode str2 '". $str2 ."'=".myhash_php($str2, $key)."<br>";
产生错误结果的当前翻译Java代码有:
public static String hash_java(String string, String key) {
//Integer strLen = byteLenUTF8(string) ; // consistent with php strlen("好友")==6
//Integer keyLen = byteLenUTF8(key) ; // byteLenUTF8("好友") == 6
Integer strLen = string.length() ; // "好友".length() == 2
Integer keyLen = key.length() ;
int j=0 ;
String hash = "" ;
int ordStr, ordKey ;
for (int i = 0; i < strLen; i++) {
ordStr = ord_java(string.substring(i,i+1)); //string is String, php substr($string,$i,$n) == java string.substring(i, i+n)
// ordStr = ord_java(string[i]); //string is byte[], php substr($string,$i,$n) == java string.substring(i, i+n)
if (j == keyLen) { j = 0; }
ordKey = ord_java(key.substring(j,j+1));
j++;
hash += strrev(base_convert(dechex(ordStr + ordKey),16,36));
}
return hash;
}
// return the ASCII code of the first character of str
public static int ord_java( String str){
return( (int) str.charAt(0) ) ;
}
public static String dechex(int input ) {
String hex = Integer.toHexString(input ) ;
return hex ;
}
public static String strrev(String str){
return new StringBuilder(str).reverse().toString() ;
}
public static String base_convert(String str, int fromBase, int toBase) {
return Integer.toString(Integer.parseInt(str, fromBase), toBase);
}
String str1 = "good friend" ;
String str2 = "好友" ;
String key = "iuyhjf476" ;
Log.d(LogTag,"java encode str1 '"+ str1 +"'="+hash_java(str1, key)) ;
Log.d(LogTag,"java encode str2 '"+ str2 +"'="+hash_java(str2, key)) ;
Java方法中UTF-8 str2的编码输出不正确。如何解决此问题?在Java中,使用UTF-8字符编码将字符串转换为字节数组。然后,将编码算法应用于这个字节数组,而不是字符串 您的PHP程序似乎隐式地执行相同的操作,例如处理字符
好根据UTF-8编码,代码>为三个单独的字节值
编辑:
在评论中,您说您收到了用户在Android上输入的字符串。因此,我们从一个来自某个UI小部件的Java字符串开始
您需要该Java字符串来提供与给定PHP函数在使用相同的UTF-8字符串时产生的结果相同的结果。结果字符串将只使用ASCII字符,因此其字符编码问题较少(不管是ISO-8859-1还是UTF-8)
PHPstring
数据类型不知道编码,只存储一个字节序列,因此通常它可能包含ISO-8859-1字节,其中一个字节表示一个字符,或UTF-8字节序列,其中字符通常占用多个字节,或任何其他编码。PHP字符串
不知道如何将字节解释为字符,它只是查看和计算字节
因此,PHP字符串所称的“字符”,实际上是UTF-8编码的字节,Java端在执行其算法时必须模拟这种行为
Java的String
数据类型与PHP非常不同,不是基于字节序列,而是(主要)将字符串视为字符序列。因此,如果使用Java字符串的字符,将不会看到PHP看到的相同元素序列
当Java在类似的字符串上迭代时好友"代码>,有两个步骤,两个字符各一个(查看字符的Unicode代码点编号),而PHP有六个步骤,UTF-8表示的每个字节一个,查看字节值
因此,要模拟PHP,在Java中必须使用UTF-8编码将字符串
转换为字节[]
数组。这样,一个Java字节
将对应一个PHP字符
评论
顺便说一句,“UTF-8字符串”在Java中没有意义
这与PHP不同,例如,“Maß”
作为ISO-8859-1字符串(长度为3)不同于“Maß”
作为UTF-8字符串(长度为4)
在Java中,字符串是字符序列,这就是为什么例如“好友“
的长度为2,因为只有两个字符恰好来自非拉丁语脚本。[对于通常遇到的大多数Unicode字符,这是正确的,但也有例外。]在Java中,UTF-8这样的术语只有在字符串和字节序列之间转换时才起作用。不用于测试-如果不完全了解您所做的事情以及文件的编码方式,这很容易产生意外的结果。对于UTF-8,您应该将所有内容都视为原始字节,并且永远不要使用字符串进行en/解码。例如PHP:
$test1 = pack( 'H*', '414243' ); // "ABC" in hexadecimal: 2 digits per byte
$test2 = pack( 'H*', 'e5a5bde58f8b' ); // "好友" in hexadecimal, UTF-8 encoded, 3 bytes per character
Java中的示例:
byte[] test1 = new byte[] { 0x41, 0x42, 0x43 }; // "ABC"
byte[] test2 = new byte[] { (byte)0xe5, (byte)0xa5, (byte)0xbd, (byte)0xe5, (byte)0x8f, (byte)0x8b }; // "好友"
只有这样,您才能确保测试设置正确,并且不受源文件编码方式的约束。如果Java文件以UTF-8编码,而PHP文件以UTF-16LE编码,那么失败的情况会更糟,因为到目前为止,您没有将定义(原始字节)和假设(基于文本编码的字符串)分开
(当人们想要对文本进行加密/解密时,这也是一个很大的误解:他们操作(任何编程语言的)String
,而不是实际的字节,然后想知道为什么不同的编程语言会产生不同的结果。)使用是一个错误——“转换”从String
到byte[]
已经太晚了。在PHP和Java中,文件的文本编码可以是任何内容-提供与任何编码无关的字节是唯一安全的方法。@AmigoJack一般来说,我同意。但是“文件的文本编码”是如何实现的呢“适用于OP的问题?文字肯定只是测试用例。我忘了在代码中输入strev方法,我添加了它。现在您可以轻松地运行代码了。如何修复java代码以使其与PHP代码一致?正如我所说的,使用UTF-8将字符串转换为字节数组,然后用等效的字节数组操作替换所有当前的字符串操作。@RalfKleberhoff我们既看不到PHP文件是否保存在UTF-8中,也看不到编码-它必须设置在某个地方,同样,由于它不在文件中,PHP文件依赖于安装。对于测试,我们必须像对待原始字节一样对待文本,而不是假设任何东西——否则测试在操作和结果上都会产生误导。什么?PHP不是应用程序,并且(除非严格用作脚本解释器)依赖于HTTP(您甚至还没有对其编码提出疑问)。了解一个范围的结束和另一个范围的开始。在Java中获取输入很容易-将其放入字符串中会导致问题,因为它不可能是UTF-8-请参阅
$test1 = pack( 'H*', '414243' ); // "ABC" in hexadecimal: 2 digits per byte
$test2 = pack( 'H*', 'e5a5bde58f8b' ); // "好友" in hexadecimal, UTF-8 encoded, 3 bytes per character
byte[] test1 = new byte[] { 0x41, 0x42, 0x43 }; // "ABC"
byte[] test2 = new byte[] { (byte)0xe5, (byte)0xa5, (byte)0xbd, (byte)0xe5, (byte)0x8f, (byte)0x8b }; // "好友"