在添加"\0"(空字符)后,是否可以向字符串中添加数据?

10
我有一个字符串,需要添加多个"\0"(空字符)到字符串中。在每个空字符之间,都有其他文本数据(只包含ASCII字母数字字符)。
我的问题是,在J2SE中添加第一个null字符(\0)时,Java似乎会确定它是字符串终止符(类似于C ++),并忽略所有其他附加的数据。不会引发错误,但后面的数据被忽略了。我需要强制在字符串中的空字符后面添加其他数据。这是我支持的遗留数据库必须这样做。
我尝试过对字符串进行编码/解码,希望像%00这样的东西会欺骗字符串行为的解释,但当我重新编码字符串时,Java再次看到空字符,并删除第一个空字符后的所有数据。
更新:这里是相关的代码片段。是的,我正在尝试使用Strings。我打算尝试使用char,但我仍然必须将其保存为字符串存储到数据库中,所以我怀疑我最终会遇到相同的问题。
一些背景信息。我通过HTTP post接收具有"\n"的数据。我需要删除换行符并用"\0"替换它们。"debug"方法只是一个简单的方法,执行System.out.println
                String[] arrLines = sValue.split("\n");
                for(int k=0;k<arrLines.length;k++) {
                    if (0<k) {
                        sNewValue += "\0";
                    }
                    sNewValue+= arrLines[k];
                    debug("New value =" + sNewValue);
                }

sNewValue是一个字符串,被提交到数据库中并需要以字符串形式完成。在每次迭代后,当我在控制台上显示sNewValue的当前值时,我观察到的情况如下:

输入值为value1\nValue2\nValue3 从这段代码输出的控制台信息如下:

value1
value1
value1

我期望

value1
value1 value2
value1 value2 value3 

在value1、value2和value3之间有不可打印的空字符\0。需要注意的是,实际保存回数据库的值也只有"value1"。因此,这不仅仅是控制台显示问题,\0后面的数据被忽略了。


在Java中,你不能说"null character"。它是一个null值,Java不使用ASCII字符,而是使用Unicode。 - Lion
1
@Lion:不对 - Unicode 中的字符 0 被称为空字符。请参见 http://www.unicode.org/charts/PDF/U0000.pdf。 - Jon Skeet
@Jon Skeet:) 谢谢你提供的信息。学到了新知识。 - Lion
1
这就是为什么我更喜欢称其为“NUL”字符,尽管它也被称为“null”字符。 - user166390
我已经更新了问题并附上了代码。 - angryITguy
显示剩余4条评论
4个回答

16

强烈怀疑这与字符串本身的文本无关,我怀疑这只是它被显示的方式。例如,尝试这样做:

public class Test {
    public static void main(String[] args) {
        String first = "first";
        String second = "second";
        String third = "third";
        String text = first + "\0" + second + "\0" + third;
        System.out.println(text.length()); // Prints 18
    }
}

这段代码输出的结果是18,表明所有字符都存在。然而,如果你尝试在UI标签中显示text,我不会感到惊讶只看到first。(同样适用于相对较弱的调试器。)

同样地,你应该能够使用:

 char c = text.charAt(7);

现在,c 应该是 'e',也就是 "second" 中的第二个字母。

基本上,我希望Java核心完全不关心它是否包含U+0000。对于Java来说,它只是另一个字符。仅当与本地代码(例如显示)的边界有关时,它可能会导致问题。

如果这不能帮助您,请确切地解释您观察到的情况-是什么让您认为其他数据没有被附加。

编辑:另一种诊断方法是打印出字符串中每个字符的Unicode值:

for (int i = 0; i < text.length(); i++) {
    System.out.println((int) text.charAt(i));
}

2
同样地,如果您使用PreparedStatement.setString()将其写入数据库中,我不确定数据库会做什么。也许使用setBytes()或setBlob()更安全。 - GeertPt
1
@ greyfairer:依我之见,如果数据库字段类型为“varchar”或类似类型,则不是这样。 - Jon Skeet
1
@giulio 你试过调试(sValue.length())吗?你会发现,这不是一个字符串问题。 - GeertPt
1
@giulio:我没有看到任何证据支持这一点,并展示了一个简短但完整的程序,显示相反的结果。你能创建一个类似的简短但完整的程序来展示出问题吗? - Jon Skeet
1
@giulio String 不会 把 \0 视为特殊字符。一个字符串中可以有任意数量的 \0 字符。但是我曾经见过用 C 写的数据库和 GUI 工具会截断带有 \0 的字符串。 - Peter Lawrey
显示剩余6条评论

2

我建议您使用char[]List<Char>,因为看起来您并不是真正使用String(一个真正的String通常不包含null或其他无法打印的字符)。


3
为什么不呢?如果 OP 想要代表这样一个字符串有一个有效的理由,并且没有技术上的原因阻止它工作,为什么要避免呢?这听起来更像是一个显示问题而已。 - Jon Skeet
这并不是一个字符序列。他在滥用 String 来保存一个以 null 为分隔符的序列。他应该创建自己的包装类。 - artbristol
1
是的,它确实是一系列字符 - 只是不可打印的字符。这样说吧:如果它是一个逗号分隔的序列,你不会感到惊讶,对吧?那么使用完全有效但不可打印的U+0000字符作为分隔符有什么大不了的呢? - Jon Skeet
@Jon 如果我需要将其写入文件以进行数据交换,则会使用逗号;但是我假设此代码用于读取空值分隔的字节流的某些遗留 API。应该通过使用 List<char[]> 或类似的东西来保护应用程序的其余部分,并且实际接口的应用程序部分可能应该使用 OutputStream。我还猜测,如果使用将空字符映射到值为 0x00 的单个字节以外的其他内容的编码,则应用程序将中断。 - artbristol
我必须使用JDK 1.4.2(令人不安)..不支持泛型。 - angryITguy
显示剩余4条评论

1

StringBuffer类的行为相同吗?

由于"\0"会造成一些麻烦,我建议不要使用它。 当实际将字符串写入您的数据库时,建议尝试用更好的分隔符替换"\0"。


0
这是因为在Java中(以及许多C相关语言中)\是转义字符,因此您需要使用额外的\进行转义,如下所示。
String str="\\0Java language";
System.out.println(str);

你应该能够在控制台上显示\0Java语言


“\”不是正则表达式,它只是字符串字面值中的转义字符。 - Jon Skeet
OP 不想在字符串中使用反斜杠后跟零 - 他想要 Unicode 空字符 U+0000。 - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接