java - Android Bug? : String.substring(5).replace(“”, “”) // empty string -


here code:

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("", "") + "["); 

and here output

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): ][         ** 

obviously, lines marked ** unexpected.

this issue happens android phone (lg p920 optimus 3d, android 2.3.3). while test on android phone b (lg e720 optimus chic, android 2.2), halts. guess runs infinite loop.

i have tested on both phones, java 1.5 , 1.6. both result in same behaviour respectively.

i have tested on same eclipse java project, 1.5, 1.6, , 1.7. of outputs correct, expected.

i wonder might device specific issue of implementing string.replace(“”, “”) against string's backing array.

could please me test in devices?

could please provide me android source code of string.replace(charsequence, charsequence) method? (like in docjar)

thanks lot!


i have modified code bit, can display on android device. (it same code anyway).

tested on both phone , phone b. behaviours still same, mentioned above.

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 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");     } } 

bingo! have found bug!

thanks @izht providing link of source code. have located bug regarding problem.

this happens when string's backing array having different (longer) value actual string. in particular, when string.offset (private variable) larger zero.

here's fix:

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 replace, return original string untouched.         return this;     }      string replacementstring = replacement.tostring();      // empty target matches @ start , end , between each character.     int targetlength = targetstring.length();     if (targetlength == 0) {         int resultlength = (count + 2) * replacementstring.length();         stringbuilder result = new stringbuilder(resultlength);         result.append(replacementstring); //        (int = offset; < count; ++i) {             // original, bug         (int = offset; < (count + offset); ++i) {    // fix             result.append(value[i]);             result.append(replacementstring);         }         return result.tostring();     }      stringbuilder result = new stringbuilder(count);     int searchstart = 0;     {         // copy characters before match...         result.append(value, offset + searchstart, matchstart - searchstart);         // insert replacement...         result.append(replacementstring);         // , skip on match...         searchstart = matchstart + targetlength;     } while ((matchstart = indexof(targetstring, searchstart)) != -1);     // copy trailing chars...     result.append(value, offset + searchstart, count - searchstart);     return result.tostring(); } 

i not sure why android has alter (and altered wrongly) replace() in way. original java implementation doesn't have issue.

by-the-way, what's now? can it? (other using replace() care, or throw away android phones :-/)


btw m quite sure lg e720 optimus chic (android 2.2) using different source code that one. keeps halting (suspect infinite looping) upon string.replace() empty target string. lately found throws error message:

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):   @ java.lang.abstractstringbuilder.enlargebuffer(abstractstringbuilder.java:97) 05-10 16:41:13.155: e/androidruntime(9384):   @ java.lang.abstractstringbuilder.append0(abstractstringbuilder.java:157) 05-10 16:41:13.155: e/androidruntime(9384):   @ java.lang.stringbuilder.append(stringbuilder.java:217) 05-10 16:41:13.155: e/androidruntime(9384):   @ java.lang.string.replace(string.java:1497) 05-10 16:41:13.155: e/androidruntime(9384):   @ com.example.testprojectnew.mainactivity.oncreate(mainactivity.java:22) 05-10 16:41:13.155: e/androidruntime(9384):   @ android.app.instrumentation.callactivityoncreate(instrumentation.java:1047) 05-10 16:41:13.155: e/androidruntime(9384):   @ android.app.activitythread.performlaunchactivity(activitythread.java:2627) 05-10 16:41:13.155: e/androidruntime(9384):   @ android.app.activitythread.handlelaunchactivity(activitythread.java:2679) 05-10 16:41:13.155: e/androidruntime(9384):   @ android.app.activitythread.access$2300(activitythread.java:125) 05-10 16:41:13.155: e/androidruntime(9384):   @ android.app.activitythread$h.handlemessage(activitythread.java:2033) 05-10 16:41:13.155: e/androidruntime(9384):   @ android.os.handler.dispatchmessage(handler.java:99) 05-10 16:41:13.155: e/androidruntime(9384):   @ android.os.looper.loop(looper.java:123) 05-10 16:41:13.155: e/androidruntime(9384):   @ android.app.activitythread.main(activitythread.java:4627) 05-10 16:41:13.155: e/androidruntime(9384):   @ java.lang.reflect.method.invokenative(native method) 05-10 16:41:13.155: e/androidruntime(9384):   @ java.lang.reflect.method.invoke(method.java:521) 05-10 16:41:13.155: e/androidruntime(9384):   @ com.android.internal.os.zygoteinit$methodandargscaller.run(zygoteinit.java:878) 05-10 16:41:13.155: e/androidruntime(9384):   @ com.android.internal.os.zygoteinit.main(zygoteinit.java:636) 05-10 16:41:13.155: e/androidruntime(9384):   @ dalvik.system.nativestart.main(native method) 

at second thought, if for-loop thingy is bug. should compile time issue. why act differently in different phones (different versions of android)?


complete workaround

got an update google, have patched it, , correct in future release.

meanwhile, have written patched method, based on their code:

(this necessary because (1) still have wait correct release, (2) need take care of devices didnt make fixed update)

/** patch string.replace(charsequence target, charsequence replacement),  *  because original buggy when charsequence target empty, i.e. "".  *  patched 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 replace, return 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();      // empty target matches @ start , end , between each character.     if (targetstring.length() == 0) {         // result contains original 'count' characters, copy of         // replacement string before every 1 of characters, , final         // copy of replacement string @ end.         final stringbuilder result = new stringbuilder(count + (count + 1) * replacementstring.length());         result.append(replacementstring);         (int = 0; < count; ++i) {             result.append(value[i]);             result.append(replacementstring);         }         return new string(result);      // stringbuilder.tostring() not give exact length     }      final stringbuilder result = new stringbuilder(count);     int searchstart = 0;     {         // copy characters before match...         result.append(value, searchstart, matchstart - searchstart);         // insert replacement...         result.append(replacementstring);         // , skip on match...         searchstart = matchstart + targetstring.length();     } while ((matchstart = string.indexof(targetstring, searchstart)) != -1);     // copy trailing chars...     result.append(value, searchstart, count - searchstart);     return new string(result);          // stringbuilder.tostring() not give exact length } 

the verbose version:

/** patch string.replace(charsequence target, charsequence replacement),  *  because original buggy when charsequence target empty, i.e. "".  *  patched 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 replace, return 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();      // empty target matches @ start , end , between each character. //    int targetlength = targetstring.length();                                   // original //    if (targetlength == 0) {                                                    // original     if (targetstring.length() == 0) { //        int resultlength = (count + 2) * replacementstring.length();            // original //        // result contains original 'count' characters, copy of //        // replacement string before every 1 of characters, , final //        // copy of replacement string @ end. //        int resultlength = count + (count + 1) * replacementstring.length();    // patched google android //        stringbuilder result = new stringbuilder(resultlength);                 // original         final stringbuilder result = new stringbuilder(count + (count + 1) * replacementstring.length());         result.append(replacementstring); //        (int = offset; < count; ++i) {                                  // original //        int end = offset + count;                                               // patched google android //        (int = offset; != end; ++i) {                                   // patched google android         (int = 0; < count; ++i) {             result.append(value[i]);             result.append(replacementstring);         } //        return result.tostring();                                               // original         return new string(result);      // stringbuilder.tostring() not give exact length     }  //    stringbuilder result = new stringbuilder(count);                            // original     final stringbuilder result = new stringbuilder(count);     int searchstart = 0;     {         // copy characters before match... //        result.append(value, offset + searchstart, matchstart - searchstart);   // original         result.append(value, searchstart, matchstart - searchstart);         // insert replacement...         result.append(replacementstring);         // , skip on match... //        searchstart = matchstart + targetlength;                                // original         searchstart = matchstart + targetstring.length(); //    } while ((matchstart = indexof(targetstring, searchstart)) != -1);          // original     } while ((matchstart = string.indexof(targetstring, searchstart)) != -1);     // copy 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() not give exact length } 

Comments

Popular posts from this blog

linux - xterm copying to CLIPBOARD using copy-selection causes automatic updating of CLIPBOARD upon mouse selection -

c++ - qgraphicsview horizontal scrolling always has a vertical delta -