在 Java 中将 UTF-8 转换为 ISO-8859-1 - 如何将其保持为单字节
Posted
技术标签:
【中文标题】在 Java 中将 UTF-8 转换为 ISO-8859-1 - 如何将其保持为单字节【英文标题】:Converting UTF-8 to ISO-8859-1 in Java - how to keep it as single byte 【发布时间】:2010-10-13 22:37:32 【问题描述】:我正在尝试将用 Java 编码的 UTF-8 字符串转换为 ISO-8859-1。例如,在字符串 'âabcd' 中,'â' 在 ISO-8859-1 中表示为 E2。在 UTF-8 中,它表示为两个字节。 C3 A2 我相信。当我执行 getbytes(encoding) 然后使用 ISO-8859-1 编码中的字节创建一个新字符串时,我得到两个不同的字符。 ¢。有没有其他方法可以做到这一点,以保持字符相同,即 âabcd?
【问题讨论】:
【参考方案1】:如果您处理的是 UTF-16 以外的字符编码,则不应使用 java.lang.String
或 char
原语 - 您应该只使用 byte[]
数组或 ByteBuffer
对象。然后,您可以使用java.nio.charset.Charset
进行编码之间的转换:
Charset utf8charset = Charset.forName("UTF-8");
Charset iso88591charset = Charset.forName("ISO-8859-1");
ByteBuffer inputBuffer = ByteBuffer.wrap(new byte[](byte)0xC3, (byte)0xA2);
// decode UTF-8
CharBuffer data = utf8charset.decode(inputBuffer);
// encode ISO-8559-1
ByteBuffer outputBuffer = iso88591charset.encode(data);
byte[] outputData = outputBuffer.array();
【讨论】:
好点,虽然我建议使用缓冲区可能并不总是最方便的方法。基本的InputStream
和OutputStream
(带有适当的包装 Readers、Writers)有时更有用,并且不需要将整个内容保存在内存中。但是哪个更方便当然取决于用例。【参考方案2】:
byte[] iso88591Data = theString.getBytes("ISO-8859-1");
会成功的。根据您的描述,您似乎正在尝试“存储 ISO-8859-1 字符串”。 Java 中的字符串对象总是以 UTF-16 隐式编码。无法更改该编码。
你可以做的,'虽然是获取构成它的其他编码的字节(使用如上所示的.getBytes()
方法)。
【讨论】:
【参考方案3】:从一组使用 UTF-8 对字符串进行编码的字节开始,从该数据创建一个字符串,然后获取一些以不同编码对字符串进行编码的字节:
byte[] utf8bytes = (byte)0xc3, (byte)0xa2, 0x61, 0x62, 0x63, 0x64 ;
Charset utf8charset = Charset.forName("UTF-8");
Charset iso88591charset = Charset.forName("ISO-8859-1");
String string = new String ( utf8bytes, utf8charset );
System.out.println(string);
// "When I do a getbytes(encoding) and "
byte[] iso88591bytes = string.getBytes(iso88591charset);
for ( byte b : iso88591bytes )
System.out.printf("%02x ", b);
System.out.println();
// "then create a new string with the bytes in ISO-8859-1 encoding"
String string2 = new String ( iso88591bytes, iso88591charset );
// "I get a two different chars"
System.out.println(string2);
这会正确输出字符串和 iso88591 字节:
âabcd
e2 61 62 63 64
âabcd
所以你的字节数组没有与正确的编码配对:
String failString = new String ( utf8bytes, iso88591charset );
System.out.println(failString);
输出
âabcd
(或者,或者您只是将 utf8 字节写入文件并在其他地方读取为 iso88591)
【讨论】:
【参考方案4】:这是我需要的:
public static byte[] encode(byte[] arr, String fromCharsetName)
return encode(arr, Charset.forName(fromCharsetName), Charset.forName("UTF-8"));
public static byte[] encode(byte[] arr, String fromCharsetName, String targetCharsetName)
return encode(arr, Charset.forName(fromCharsetName), Charset.forName(targetCharsetName));
public static byte[] encode(byte[] arr, Charset sourceCharset, Charset targetCharset)
ByteBuffer inputBuffer = ByteBuffer.wrap( arr );
CharBuffer data = sourceCharset.decode(inputBuffer);
ByteBuffer outputBuffer = targetCharset.encode(data);
byte[] outputData = outputBuffer.array();
return outputData;
【讨论】:
【参考方案5】:如果你在字符串中有正确的编码,你不需要做更多的事情来获取另一个编码的字节。
public static void main(String[] args) throws Exception
printBytes("â");
System.out.println(
new String(new byte[] (byte) 0xE2 , "ISO-8859-1"));
System.out.println(
new String(new byte[] (byte) 0xC3, (byte) 0xA2 , "UTF-8"));
private static void printBytes(String str)
System.out.println("Bytes in " + str + " with ISO-8859-1");
for (byte b : str.getBytes(StandardCharsets.ISO_8859_1))
System.out.printf("%3X", b);
System.out.println();
System.out.println("Bytes in " + str + " with UTF-8");
for (byte b : str.getBytes(StandardCharsets.UTF_8))
System.out.printf("%3X", b);
System.out.println();
输出:
Bytes in â with ISO-8859-1
E2
Bytes in â with UTF-8
C3 A2
â
â
【讨论】:
【参考方案6】:对于文件编码...
public class FRomUtf8ToIso
static File input = new File("C:/Users/admin/Desktop/pippo.txt");
static File output = new File("C:/Users/admin/Desktop/ciccio.txt");
public static void main(String[] args) throws IOException
BufferedReader br = null;
FileWriter fileWriter = new FileWriter(output);
try
String sCurrentLine;
br = new BufferedReader(new FileReader( input ));
int i= 0;
while ((sCurrentLine = br.readLine()) != null)
byte[] isoB = encode( sCurrentLine.getBytes() );
fileWriter.write(new String(isoB, Charset.forName("ISO-8859-15") ) );
fileWriter.write("\n");
System.out.println( i++ );
catch (IOException e)
e.printStackTrace();
finally
try
fileWriter.flush();
fileWriter.close();
if (br != null)br.close();
catch (IOException ex)
ex.printStackTrace();
static byte[] encode(byte[] arr)
Charset utf8charset = Charset.forName("UTF-8");
Charset iso88591charset = Charset.forName("ISO-8859-15");
ByteBuffer inputBuffer = ByteBuffer.wrap( arr );
// decode UTF-8
CharBuffer data = utf8charset.decode(inputBuffer);
// encode ISO-8559-1
ByteBuffer outputBuffer = iso88591charset.encode(data);
byte[] outputData = outputBuffer.array();
return outputData;
【讨论】:
【参考方案7】:除了亚当·罗森菲尔德的回答,我想补充一点,ByteBuffer.array()
返回缓冲区的底层字节数组,不一定要“修剪”到最后一个字符。需要额外的操作,例如this答案中提到的那些;特别是:
byte[] b = new byte[bb.remaining()]
bb.get(b);
【讨论】:
【参考方案8】:驱逐非 ISO-8859-1 字符,将被替换为 '?' (例如发送到 ISO-8859-1 数据库之前):
utf8String = new String (utf8String.getBytes(), "ISO-8859-1" );
【讨论】:
用?
替换所有非 ASCII 字符似乎是一个糟糕的解决方案,因为它可以在不丢失字符串的情况下进行转换。
@s4y 你是对的,这似乎是一个糟糕的解决方案,但想想 ASCII。您根本不能在 ASCII 中使用变音符号。您将不得不对无法编码的字符进行something。对于手头的问题,这是最简单且正确的解决方案。可以考虑使用 StandardCharsets.ISO_8859_1。
@fahrradfahrer 对于它的价值,如果我今天写那条评论,我就不会使用“可怕”这个词!但对于这种情况,我可能会选择***.com/a/14121678/84745 之类的东西,它本质上为您提供了 ASCII 字符串的近似值。以上是关于在 Java 中将 UTF-8 转换为 ISO-8859-1 - 如何将其保持为单字节的主要内容,如果未能解决你的问题,请参考以下文章