Java String replace substring by substring
public class Main { public static void main(String[] argv) throws Exception { String text = "CSS CSS HTML HTML Java Java"; String[] searchList = new String[] { "CSS", "HTML", "Java" }; String[] replacementList = new String[] { "css", "html", "javascript" }; System.out.println(replaceEachRepeatedly(text, searchList, replacementList)); }//from www .j a v a 2 s . c o m /** * <p> * Replaces all occurrences of Strings within another String. * </p> * * <p> * A <code>null</code> reference passed to this method is a no-op, or if any * "search string" or "string to replace" is null, that replace will be ignored. * This will not repeat. For repeating replaces, call the overloaded method. * </p> * * <pre> * replaceEach(null, *, *, *) = null * replaceEach("", *, *, *) = "" * replaceEach("aba", null, null, *) = "aba" * replaceEach("aba", new String[0], null, *) = "aba" * replaceEach("aba", null, new String[0], *) = "aba" * replaceEach("aba", new String[]{"a"}, null, *) = "aba" * replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b" * replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba" * replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte" * (example of how it repeats) * replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte" * replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte" * replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, true) = IllegalArgumentException * replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, false) = "dcabe" * </pre> * * @param text * text to search and replace in, no-op if null * @param searchList * the Strings to search for, no-op if null * @param replacementList * the Strings to replace them with, no-op if null * @return the text with any replacements processed, <code>null</code> if null * String input * @throws IllegalArgumentException * if the search is repeating and there is an endless loop due to * outputs of one being inputs to another * @throws IndexOutOfBoundsException * if the lengths of the arrays are not the same (null is ok, and/or * size 0) * @since 2.4 */ public static String replaceEachRepeatedly(String text, String[] searchList, String[] replacementList) { // timeToLive should be 0 if not used or nothing to replace, else it's // the length of the replace array int timeToLive = searchList == null ? 0 : searchList.length; return replaceEach(text, searchList, replacementList, true, timeToLive); } /** * <pre> * replaceEach(null, *, *) = null * replaceEach("", *, *) = "" * replaceEach("aba", null, null) = "aba" * replaceEach("aba", new String[0], null) = "aba" * replaceEach("aba", null, new String[0]) = "aba" * replaceEach("aba", new String[]{"a"}, null) = "aba" * replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b" * replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba" * replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" * (example of how it does not repeat) * replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte" * </pre> */ public static String replaceEach(String text, String[] searchList, String[] replacementList) { return replaceEach(text, searchList, replacementList, false, 0); } /** * <pre> * replaceEach(null, *, *, *) = null * replaceEach("", *, *, *) = "" * replaceEach("aba", null, null, *) = "aba" * replaceEach("aba", new String[0], null, *) = "aba" * replaceEach("aba", null, new String[0], *) = "aba" * replaceEach("aba", new String[]{"a"}, null, *) = "aba" * replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b" * replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba" * replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte" * (example of how it repeats) * replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte" * replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte" * replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *) = IllegalArgumentException * </pre> */ private static String replaceEach(String text, String[] searchList, String[] replacementList, boolean repeat, int timeToLive) { // mchyzer Performance note: This creates very few new objects (one major goal) // let me know if there are performance requests, we can create a harness to // measure if (text == null || text.length() == 0 || searchList == null || searchList.length == 0 || replacementList == null || replacementList.length == 0) { return text; } // if recursing, this shouldnt be less than 0 if (timeToLive < 0) { throw new IllegalStateException("TimeToLive of " + timeToLive + " is less than 0: " + text); } int searchLength = searchList.length; int replacementLength = replacementList.length; // make sure lengths are ok, these need to be equal if (searchLength != replacementLength) { throw new IllegalArgumentException( "Search and Replace array lengths don't match: " + searchLength + " vs " + replacementLength); } // keep track of which still have matches boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; // index on index that the match was found int textIndex = -1; int replaceIndex = -1; int tempIndex = -1; // index of replace array that will replace the search string found // NOTE: logic duplicated below START for (int i = 0; i < searchLength; i++) { if (noMoreMatchesForReplIndex[i] || searchList[i] == null || searchList[i].length() == 0 || replacementList[i] == null) { continue; } tempIndex = text.indexOf(searchList[i]); // see if we need to keep searching for this if (tempIndex == -1) { noMoreMatchesForReplIndex[i] = true; } else { if (textIndex == -1 || tempIndex < textIndex) { textIndex = tempIndex; replaceIndex = i; } } } // NOTE: logic mostly below END // no search strings found, we are done if (textIndex == -1) { return text; } int start = 0; // get a good guess on the size of the result buffer so it doesnt have to double // if it goes over a bit int increase = 0; // count the replacement text elements that are larger than their corresponding // text being replaced for (int i = 0; i < searchList.length; i++) { int greater = replacementList[i].length() - searchList[i].length(); if (greater > 0) { increase += 3 * greater; // assume 3 matches } } // have upper-bound at 20% increase, then let Java take over increase = Math.min(increase, text.length() / 5); StringBuffer buf = new StringBuffer(text.length() + increase); while (textIndex != -1) { for (int i = start; i < textIndex; i++) { buf.append(text.charAt(i)); } buf.append(replacementList[replaceIndex]); start = textIndex + searchList[replaceIndex].length(); textIndex = -1; replaceIndex = -1; tempIndex = -1; // find the next earliest match // NOTE: logic mostly duplicated above START for (int i = 0; i < searchLength; i++) { if (noMoreMatchesForReplIndex[i] || searchList[i] == null || searchList[i].length() == 0 || replacementList[i] == null) { continue; } tempIndex = text.indexOf(searchList[i], start); // see if we need to keep searching for this if (tempIndex == -1) { noMoreMatchesForReplIndex[i] = true; } else { if (textIndex == -1 || tempIndex < textIndex) { textIndex = tempIndex; replaceIndex = i; } } } // NOTE: logic duplicated above END } int textLength = text.length(); for (int i = start; i < textLength; i++) { buf.append(text.charAt(i)); } String result = buf.toString(); if (!repeat) { return result; } return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); } } /* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */