假设我有以下字符串:RückrufinsAusland 我需要将其插入到最大大小为10的数据库中。 我在java中做了一个普通的子字符串,它在中提取了这个字符串Rückruf,这是10个字符。当它试图插入此列时,我得到以下oracle错误:
java.sql.SQLException:ORA-12899:值对于列来说太大了 “WAEL”。“TESTTBL”。“DESC”(实际:11,最大值:10) 原因是数据库有一个AL32UTF8字符集,因此ü将采用2个字符。
我需要在java中编写一个执行此子字符串的函数,但考虑到ü占用2个字节,因此在这种情况下返回的子字符串应该是Rückrufi(9个字符)。有什么建议吗?
答案 0 :(得分:2)
您可以在java中将字符串转换为字节数组来计算String
的正确长度。
作为示例,请参阅以下代码:
System.out.println("Rückruf i".length()); // prints 9
System.out.println("Rückruf i".getBytes().length); // prints 10
如果当前字符集不是UTF-8,请将代码替换为:
System.out.println("Rückruf i".length()); // prints 9
System.out.println("Rückruf i".getBytes("UTF-8").length); // prints 10
如果需要,您可以使用您喜欢的字符集替换UTF-8,以测试该字符集中字符串的长度。
答案 1 :(得分:2)
如果它必须是Java,你可以将字符串解析为字节并修剪数组的长度。
String s = "Rückruf ins Ausland";
byte[] bytes = s.getBytes("UTF-8");
byte[] bytes2 = new byte[10];
System.arraycopy(bytes, 0, bytes2, 0, 10);
String trim = new String(bytes2, "UTF-8");
答案 2 :(得分:1)
我认为在这种情况下最好的选择是在数据库级别进行子串,使用Oracle SUBSTR函数直接在SQL QUERY上。
例如:
INSERT INTO ttable (colname) VALUES (SUBSTR( ?, 1, 10 ))
感叹号代表通过JDBC发送的SQL参数。
答案 3 :(得分:1)
如果你想修剪Java中的数据,你必须编写一个使用db charset修剪字符串的函数,类似于这个测试用例:
package test;
import java.io.UnsupportedEncodingException;
public class TrimField {
public static void main(String[] args) {
//UTF-8 is the db charset
System.out.println(trim("Rückruf ins Ausland",10,"UTF-8"));
System.out.println(trim("Rüückruf ins Ausland",10,"UTF-8"));
}
public static String trim(String value, int numBytes, String charset) {
do {
byte[] valueInBytes = null;
try {
valueInBytes = value.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage(), e);
}
if (valueInBytes.length > numBytes) {
value = value.substring(0, value.length() - 1);
} else {
return value;
}
} while (value.length() > 0);
return "";
}
}
答案 4 :(得分:1)
以下可怕的情况是通过完整的Unicode代码点遍历整个字符串,所以也是char对(代理代码点)。
public String trim(String s, int length) {
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
if (bytes.length <= length) {
return s;
}
int totalByteCount = 0;
for (int i = 0; i < s.length(); ) {
int cp = s.codePointAt(i);
int n = Character.charCount(cp);
int byteCount = s.substring(i, i + n)
.getBytes(StandardCharsets.UTF_8).length;
if (totalByteCount + byteCount) > length) {
break;
}
totalByteCount += byteCount;
i += n;
}
return new String(bytes, 0, totalByteCount);
}
它仍然可以进行一些优化。
答案 5 :(得分:0)
您需要让数据库中的编码与java字符串的编码匹配。或者,您可以使用this之类的内容转换字符串,并获取与数据库中的编码匹配的长度。这将为您提供准确的字节数。否则,你仍然只是希望编码匹配。
String string = "Rückruf ins Ausland";
int curByteCount = 0;
String nextChar;
for(int index = 0; curByteCount +
(nextChar = string.substr(index,index + 1)).getBytes("UTF-8").length < trimmedBytes.length; index++){
curByteCount += nextChar.getBytes("UTF-8").length;
}
byte[] subStringBytes = new byte[10];
System.arraycopy(string.getBytes("UTF-8"), 0, subStringBytes, 0, curByteCount);
String trimed = new String(subStringBytes, "UTF-8");
这应该这样做。它也不应该在这个过程中截断一个多字节字符。这里的假设是数据库是UTF-8编码。另一个假设是实际需要修剪字符串。
答案 6 :(得分:0)
嘿所有ASCII字符都小于128.您可以使用以下代码。
public class Test {
public static void main(String[] args) {
String s= "Rückruf ins Ausland";
int length =10;
for(int i=0;i<s.length();i++){
if(!(((int)s.charAt(i))<128)){
length--;
}
}
System.out.println(s.substring(0,length));
}
}
您可以复制粘贴并检查它是否满足您的需要,或者它在任何地方都会中断。