java - 安卓有bug吗? : String. substring(5).replace (“” , “” )//空字符串

标签 java android string substring str-replace

这是我的代码:

String str = "just_a_string";
System.out.println("]" + str + "[");
System.out.println("]" + str.replace("", "") + "[");
System.out.println("]" + str.substring(5) + "[");
System.out.println("]" + str.substring(5).replace("", "") + "[");
System.out.println("]" + str.substring(3, 8) + "[");
System.out.println("]" + str.substring(3, 8).replace("", "") + "[");
System.out.println("]" + "sdajndan".substring(5).replace("", "") + "[");

这是输出

05-09 19:09:20.570: I/System.out(23801): ]just_a_string[
05-09 19:09:20.570: I/System.out(23801): ]just_a_string[
05-09 19:09:20.570: I/System.out(23801): ]a_string[
05-09 19:09:20.570: I/System.out(23801): ]a_s[      **
05-09 19:09:20.570: I/System.out(23801): ]t_a_s[
05-09 19:09:20.570: I/System.out(23801): ]t_[       **
05-09 19:09:20.570: I/System.out(23801): ][         **

显然,标有**的行是意外的。

此问题发生在我的 Android 手机 A(LG P920 Optimus 3D,Android 2.3.3)上。当我在 Android 手机 B(LG E720 Optimus Chic,Android 2.2)上进行测试时,它停止了。我猜它会陷入无限循环。

我已经在两部手机上进行了测试,分别使用 Java 1.51.6。两者分别导致相同的行为。

我还在同一个 Eclipse 上使用 Java 项目测试了 1.51.61.7。正如预期的那样,他们的所有输出都是正确的。

我想知道这可能是针对字符串的 backing array 实现 String.replace(“”, “”) 的设备特定问题。 .

您能帮我在您的设备上进行测试吗?

有人可以向我提供 String.replace(CharSequence, CharSequence) 方法的 Android 源代码吗? (就像 docjar 中的内容)

非常感谢!


我对代码做了一些修改,所以它也可以在Android设备上显示。 (无论如何,这只是相同的代码)。

在我的手机 A 和手机 B 上进行了测试。如上所述,行为仍然相同。

package com.example.testprojectnew;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

    String output_text = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String str = "just_a_string";
        process("1]" + str + "[");
        process("2]" + str.replace("", "") + "[");
        process("3]" + str.substring(5) + "[");
        process("4]" + str.substring(5).replace("", "") + "[");
        process("5]" + str.substring(3, 8) + "[");
        process("6]" + str.substring(3, 8).replace("", "") + "[");
        process("7]" + "sdajndan".substring(5).replace("", "") + "[");

        output_text = output_text.concat("\n\nLines (1 & 2), (3 & 4), (5 & 6), should be the same.");

        ((TextView) findViewById(R.id.a_string)).setText(output_text);
    }
    private void process(String str) {
        System.out.println(str);
        output_text = output_text.concat(str).concat("\n");
    }
}

最佳答案

宾果游戏!我发现了这个错误!

感谢@izht提供source code的链接。我已经找到了有关此问题的错误。

这只发生在字符串 backing array 时具有与实际字符串不同(更长)的值。特别是,当String.offset(私有(private)变量)大于零时。

修复方法如下:

public String replace(CharSequence target, CharSequence replacement) {
    if (target == null) {
        throw new NullPointerException("target == null");
    }
    if (replacement == null) {
        throw new NullPointerException("replacement == null");
    }

    String targetString = target.toString();
    int matchStart = indexOf(targetString, 0);
    if (matchStart == -1) {
        // If there's nothing to replace, return the original string untouched.
        return this;
    }

    String replacementString = replacement.toString();

    // The empty target matches at the start and end and between each character.
    int targetLength = targetString.length();
    if (targetLength == 0) {
        int resultLength = (count + 2) * replacementString.length();
        StringBuilder result = new StringBuilder(resultLength);
        result.append(replacementString);
//        for (int i = offset; i < count; ++i) {             // original, bug
        for (int i = offset; i < (count + offset); ++i) {    // fix
            result.append(value[i]);
            result.append(replacementString);
        }
        return result.toString();
    }

    StringBuilder result = new StringBuilder(count);
    int searchStart = 0;
    do {
        // Copy characters before the match...
        result.append(value, offset + searchStart, matchStart - searchStart);
        // Insert the replacement...
        result.append(replacementString);
        // And skip over the match...
        searchStart = matchStart + targetLength;
    } while ((matchStart = indexOf(targetString, searchStart)) != -1);
    // Copy any trailing chars...
    result.append(value, offset + searchStart, count - searchStart);
    return result.toString();
}

我不确定为什么 Android 必须以这种方式更改(并且错误地更改)replace()。原来的Java实现没有这个问题。

顺便问一下,现在怎么样?我可以用它做什么? (除了格外小心地使用 replace() 或扔掉我的 Android 手机:-/)


顺便说一句,我很确定我的 LG E720 Optimus Chic (Android 2.2) 使用的源代码与 that one 不同。 。当 String.replace() 目标字符串为空时,它会不断停止(怀疑是无限循环)。最近我发现它抛出此错误消息:

05-10 16:41:13.155: E/AndroidRuntime(9384): FATAL EXCEPTION: main
05-10 16:41:13.155: E/AndroidRuntime(9384): java.lang.OutOfMemoryError
05-10 16:41:13.155: E/AndroidRuntime(9384):   at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:97)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:157)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at java.lang.StringBuilder.append(StringBuilder.java:217)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at java.lang.String.replace(String.java:1497)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at com.example.testprojectnew.MainActivity.onCreate(MainActivity.java:22)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at android.app.ActivityThread.access$2300(ActivityThread.java:125)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at android.os.Handler.dispatchMessage(Handler.java:99)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at android.os.Looper.loop(Looper.java:123)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at android.app.ActivityThread.main(ActivityThread.java:4627)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at java.lang.reflect.Method.invokeNative(Native Method)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at java.lang.reflect.Method.invoke(Method.java:521)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:878)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)
05-10 16:41:13.155: E/AndroidRuntime(9384):   at dalvik.system.NativeStart.main(Native Method)

再想一想,如果那个 for 循环 的错误。应该是编译时的问题。为什么它在不同手机(不同版本的 Android)中会有不同的表现?


完整的解决方法

得到an update来自 Google,他们已经修补了它,并将更正它 in the future release .

同时,我编写了一个基于 their code 的修补方法。 :

(这是必要的,因为(1)我们仍然需要等待正确的版本,(2)我们需要照顾没有进行固定更新的设备)

/** Patch for the String.replace(CharSequence target, CharSequence replacement),
 *  because the original is buggy when CharSequence target is empty, i.e. "".
 *  Patched by Google Android: https://android-review.googlesource.com/58393
 */
public static String replacePatched(final String string, final CharSequence target, final CharSequence replacement) {
    if (target == null) {
        throw new NullPointerException("target == null");
    }
    if (replacement == null) {
        throw new NullPointerException("replacement == null");
    }

    final String targetString = target.toString();
    int matchStart = string.indexOf(targetString, 0);
    if (matchStart == -1) {
        // If there's nothing to replace, return the original string untouched.
        return new String(string);
    }

    final char[] value = string.toCharArray();                              // required in patch
    final int count = value.length;                                         // required in patch

    final String replacementString = replacement.toString();

    // The empty target matches at the start and end and between each character.
    if (targetString.length() == 0) {
        // The result contains the original 'count' characters, a copy of the
        // replacement string before every one of those characters, and a final
        // copy of the replacement string at the end.
        final StringBuilder result = new StringBuilder(count + (count + 1) * replacementString.length());
        result.append(replacementString);
        for (int i = 0; i < count; ++i) {
            result.append(value[i]);
            result.append(replacementString);
        }
        return new String(result);      // StringBuilder.toString() does not give exact length
    }

    final StringBuilder result = new StringBuilder(count);
    int searchStart = 0;
    do {
        // Copy characters before the match...
        result.append(value, searchStart, matchStart - searchStart);
        // Insert the replacement...
        result.append(replacementString);
        // And skip over the match...
        searchStart = matchStart + targetString.length();
    } while ((matchStart = string.indexOf(targetString, searchStart)) != -1);
    // Copy any trailing chars...
    result.append(value, searchStart, count - searchStart);
    return new String(result);          // StringBuilder.toString() does not give exact length
}

详细版本:

/** Patch for the String.replace(CharSequence target, CharSequence replacement),
 *  because the original is buggy when CharSequence target is empty, i.e. "".
 *  Patched by Google Android: https://android-review.googlesource.com/58393
 */
public static String replacePatched(final String string, final CharSequence target, final CharSequence replacement) {
    if (target == null) {
        throw new NullPointerException("target == null");
    }
    if (replacement == null) {
        throw new NullPointerException("replacement == null");
    }

//    String targetString = target.toString();                                    // original
    final String targetString = target.toString();
//    int matchStart = indexOf(targetString, 0);                                  // original
    int matchStart = string.indexOf(targetString, 0);
    if (matchStart == -1) {
        // If there's nothing to replace, return the original string untouched.
//        return this;                                                            // original
        return new String(string);
    }

    final char[] value = string.toCharArray();                              // required in patch
    final int count = value.length;                                         // required in patch

//    String replacementString = replacement.toString();                          // original
    final String replacementString = replacement.toString();

    // The empty target matches at the start and end and between each character.
//    int targetLength = targetString.length();                                   // original
//    if (targetLength == 0) {                                                    // original
    if (targetString.length() == 0) {
//        int resultLength = (count + 2) * replacementString.length();            // original
//        // The result contains the original 'count' characters, a copy of the
//        // replacement string before every one of those characters, and a final
//        // copy of the replacement string at the end.
//        int resultLength = count + (count + 1) * replacementString.length();    // patched by Google Android
//        StringBuilder result = new StringBuilder(resultLength);                 // original
        final StringBuilder result = new StringBuilder(count + (count + 1) * replacementString.length());
        result.append(replacementString);
//        for (int i = offset; i < count; ++i) {                                  // original
//        int end = offset + count;                                               // patched by Google Android
//        for (int i = offset; i != end; ++i) {                                   // patched by Google Android
        for (int i = 0; i < count; ++i) {
            result.append(value[i]);
            result.append(replacementString);
        }
//        return result.toString();                                               // original
        return new String(result);      // StringBuilder.toString() does not give exact length
    }

//    StringBuilder result = new StringBuilder(count);                            // original
    final StringBuilder result = new StringBuilder(count);
    int searchStart = 0;
    do {
        // Copy characters before the match...
//        result.append(value, offset + searchStart, matchStart - searchStart);   // original
        result.append(value, searchStart, matchStart - searchStart);
        // Insert the replacement...
        result.append(replacementString);
        // And skip over the match...
//        searchStart = matchStart + targetLength;                                // original
        searchStart = matchStart + targetString.length();
//    } while ((matchStart = indexOf(targetString, searchStart)) != -1);          // original
    } while ((matchStart = string.indexOf(targetString, searchStart)) != -1);
    // Copy any trailing chars...
//    result.append(value, offset + searchStart, count - searchStart);            // original
    result.append(value, searchStart, count - searchStart);
//    return result.toString();                                                   // original
    return new String(result);          // StringBuilder.toString() does not give exact length
}

关于java - 安卓有bug吗? : String. substring(5).replace (“” , “” )//空字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16475317/

相关文章:

java - Gson 无法使用自定义序列化程序进行反序列化

android - 从 Twitter 检索有限数量的直接消息

java - 如何使用复选框获取所有选定的列表项

Java正则表达式转换

java - 安卓相机按钮

java - 如何等待Java中线程的启动

c - 错误 234 "More data is available"与 GetComputerNameEx

c# - 对查询字符串 ABC 顺序进行排序(使用 Unix 风格区分大小写的排序顺序),不带分隔符

java - 尝试从 ArrayList 在 Struts2 中创建表

android - 除了后缀资源文件夹(values-es)之外还需要什么来支持应用程序(Android)中的多种语言?