한 줄이 다른 줄을 바꾸지 않는 방법으로 두 줄을 어떻게 바꿀 수 있습니까?
다음 코드가 있다고 가정 해 봅시다.
String word1 = "bar";
String word2 = "foo";
String story = "Once upon a time, there was a foo and a bar."
story = story.replace("foo", word1);
story = story.replace("bar", word2);
이 코드를 실행 한 후,의 값이 story
될 것입니다"Once upon a time, there was a foo and a foo."
반대 순서로 교체하면 비슷한 문제가 발생합니다.
String word1 = "bar";
String word2 = "foo";
String story = "Once upon a time, there was a foo and a bar."
story = story.replace("bar", word2);
story = story.replace("foo", word1);
의 값이 story
됩니다"Once upon a time, there was a bar and a bar."
내 목표는 설정하는 것입니다 story
으로 "Once upon a time, there was a bar and a foo."
나는 그것을 달성 할 수 있는가?
Apache Commons StringUtils 의 replaceEach()
메소드를 사용하십시오 .
StringUtils.replaceEach(story, new String[]{"foo", "bar"}, new String[]{"bar", "foo"})
문장에 아직없는 중간 값을 사용합니다.
story = story.replace("foo", "lala");
story = story.replace("bar", "foo");
story = story.replace("lala", "bar");
비판에 대한 응답으로 : zq515sqdqs5d5sq1dqs4d1q5dqqé "& é5d4sqjshsjddjhodfqsqc, nvùq ^ µù; d & € sdq : d :;) àçàçlala 와 같이 충분히 드문 문자열을 사용하는 경우 에는 아무 말도 하지 않습니다 사용자가 입력 할 것인지 알 수있는 유일한 방법은 소스 코드를 알고 그 시점에서 완전히 다른 수준의 걱정을하는 것입니다.
예, 아마도 멋진 정규식 방법이있을 수 있습니다. 나는 읽을 수있는 것을 선호한다.
또한 의견 에 @David Conrad가 제공 한 훌륭한 조언을 반복합니다 .
가능성이없는 것으로 현명하게 (멍청하게) 선택된 문자열을 사용하지 마십시오. 유니 코드 개인 사용 영역 (U + E000..U + F8FF)의 문자를 사용하십시오. 이러한 문자는 합법적으로 입력에 포함되지 않아야하기 때문에 먼저 제거하고 (일부 응용 프로그램 내에서 응용 프로그램 특정 의미 만 있음) 교체 할 때 자리 표시 자로 사용하십시오.
Matcher#appendReplacement
and를 사용하여 이와 같은 것을 시도 할 수 있습니다 Matcher#appendTail
.
String word1 = "bar";
String word2 = "foo";
String story = "Once upon a time, there was a foo and a bar.";
Pattern p = Pattern.compile("foo|bar");
Matcher m = p.matcher(story);
StringBuffer sb = new StringBuffer();
while (m.find()) {
/* do the swap... */
switch (m.group()) {
case "foo":
m.appendReplacement(sb, word1);
break;
case "bar":
m.appendReplacement(sb, word2);
break;
default:
/* error */
break;
}
}
m.appendTail(sb);
System.out.println(sb.toString());
옛날 옛적에 술집과 foo가있었습니다.
이것은 쉬운 문제가 아닙니다. 검색 대체 매개 변수가 많을수록 더 까다로워집니다. 추악하고 우아하고 효율적으로 낭비되는 팔레트에 여러 가지 옵션이 있습니다.
@AlanHay가 권장 되는대로
StringUtils.replaceEach
Apache Commons에서 사용하십시오 . 프로젝트에 새로운 의존성을 추가 할 수 있다면 좋은 옵션입니다. 운이 좋을 수도 있습니다 : 종속성이 이미 프로젝트에 포함되었을 수 있습니다@Jeroen이 제안한 대로 임시 자리 표시자를 사용하고 2 단계로 교체를 수행하십시오.
- 모든 검색 패턴을 원본 텍스트에없는 고유 한 태그로 바꿉니다.
- 자리 표시자를 실제 대상 교체로 교체
이는 여러 가지 이유로 큰 접근 방식이 아닙니다. 첫 번째 단계에서 사용 된 태그가 실제로 고유한지 확인해야합니다. 실제로 필요한 것보다 더 많은 문자열 교체 작업을 수행합니다.
모든 패턴에서 정규식을 구축하고 함께 방법을 사용
Matcher
하고StringBuffer
등이 제안 @arshajii . 이 끔찍한되지 않습니다,하지만 그 큰 중 하나, 정규식을 구축하는 것은 일종의 hackish의, 그리고이 포함로StringBuffer
찬성 얼마 전 패션 A의 나갔다한다StringBuilder
.@mjolka가 제안한 재귀 솔루션을 사용 하여 일치하는 패턴으로 문자열을 분할하고 나머지 세그먼트를 반복하십시오 . 이것은 작고 매우 우아한 훌륭한 솔루션입니다. 약점은 잠재적으로 많은 부분 문자열 및 연결 작업이며 모든 재귀 솔루션에 적용되는 스택 크기 제한입니다.
@msandiford가 제안한 대로 텍스트를 단어로 나누고 Java 8 스트림을 사용하여 교체를 우아하게 수행 하지만 단어 경계에서 분할해도 괜찮은 경우에만 작동하므로 일반적인 솔루션으로는 적합하지 않습니다.
다음은 Apache 구현 에서 빌린 아이디어를 기반으로 한 내 버전 입니다. 단순하거나 우아하지는 않지만 작동하지만 불필요한 단계없이 비교적 효율적이어야합니다. 간단히 말해서, 그것은 다음과 같이 작동합니다 : 텍스트에서 다음으로 일치하는 검색 패턴을 반복적으로 찾고 a StringBuilder
를 사용하여 일치하지 않는 세그먼트와 대체물을 누적하십시오.
public static String replaceEach(String text, String[] searchList, String[] replacementList) {
// TODO: throw new IllegalArgumentException() if any param doesn't make sense
//validateParams(text, searchList, replacementList);
SearchTracker tracker = new SearchTracker(text, searchList, replacementList);
if (!tracker.hasNextMatch(0)) {
return text;
}
StringBuilder buf = new StringBuilder(text.length() * 2);
int start = 0;
do {
SearchTracker.MatchInfo matchInfo = tracker.matchInfo;
int textIndex = matchInfo.textIndex;
String pattern = matchInfo.pattern;
String replacement = matchInfo.replacement;
buf.append(text.substring(start, textIndex));
buf.append(replacement);
start = textIndex + pattern.length();
} while (tracker.hasNextMatch(start));
return buf.append(text.substring(start)).toString();
}
private static class SearchTracker {
private final String text;
private final Map<String, String> patternToReplacement = new HashMap<>();
private final Set<String> pendingPatterns = new HashSet<>();
private MatchInfo matchInfo = null;
private static class MatchInfo {
private final String pattern;
private final String replacement;
private final int textIndex;
private MatchInfo(String pattern, String replacement, int textIndex) {
this.pattern = pattern;
this.replacement = replacement;
this.textIndex = textIndex;
}
}
private SearchTracker(String text, String[] searchList, String[] replacementList) {
this.text = text;
for (int i = 0; i < searchList.length; ++i) {
String pattern = searchList[i];
patternToReplacement.put(pattern, replacementList[i]);
pendingPatterns.add(pattern);
}
}
boolean hasNextMatch(int start) {
int textIndex = -1;
String nextPattern = null;
for (String pattern : new ArrayList<>(pendingPatterns)) {
int matchIndex = text.indexOf(pattern, start);
if (matchIndex == -1) {
pendingPatterns.remove(pattern);
} else {
if (textIndex == -1 || matchIndex < textIndex) {
textIndex = matchIndex;
nextPattern = pattern;
}
}
}
if (nextPattern != null) {
matchInfo = new MatchInfo(nextPattern, patternToReplacement.get(nextPattern), textIndex);
return true;
}
return false;
}
}
단위 테스트 :
@Test
public void testSingleExact() {
assertEquals("bar", StringUtils.replaceEach("foo", new String[]{"foo"}, new String[]{"bar"}));
}
@Test
public void testReplaceTwice() {
assertEquals("barbar", StringUtils.replaceEach("foofoo", new String[]{"foo"}, new String[]{"bar"}));
}
@Test
public void testReplaceTwoPatterns() {
assertEquals("barbaz", StringUtils.replaceEach("foobar",
new String[]{"foo", "bar"},
new String[]{"bar", "baz"}));
}
@Test
public void testReplaceNone() {
assertEquals("foofoo", StringUtils.replaceEach("foofoo", new String[]{"x"}, new String[]{"bar"}));
}
@Test
public void testStory() {
assertEquals("Once upon a foo, there was a bar and a baz, and another bar and a cat.",
StringUtils.replaceEach("Once upon a baz, there was a foo and a bar, and another foo and a cat.",
new String[]{"foo", "bar", "baz"},
new String[]{"bar", "baz", "foo"})
);
}
대체 할 첫 단어를 검색하십시오. 문자열에 있으면 발생 전 문자열 부분과 발생 후 문자열 부분에서 되풀이하십시오.
그렇지 않으면 다음 단어를 계속 바꾸십시오.
순진한 구현은 다음과 같습니다.
public static String replaceAll(String input, String[] search, String[] replace) {
return replaceAll(input, search, replace, 0);
}
private static String replaceAll(String input, String[] search, String[] replace, int i) {
if (i == search.length) {
return input;
}
int j = input.indexOf(search[i]);
if (j == -1) {
return replaceAll(input, search, replace, i + 1);
}
return replaceAll(input.substring(0, j), search, replace, i + 1) +
replace[i] +
replaceAll(input.substring(j + search[i].length()), search, replace, i);
}
샘플 사용법 :
String input = "Once upon a baz, there was a foo and a bar.";
String[] search = new String[] { "foo", "bar", "baz" };
String[] replace = new String[] { "bar", "baz", "foo" };
System.out.println(replaceAll(input, search, replace));
산출:
Once upon a foo, there was a bar and a baz.
덜 순진한 버전 :
public static String replaceAll(String input, String[] search, String[] replace) {
StringBuilder sb = new StringBuilder();
replaceAll(sb, input, 0, input.length(), search, replace, 0);
return sb.toString();
}
private static void replaceAll(StringBuilder sb, String input, int start, int end, String[] search, String[] replace, int i) {
while (i < search.length && start < end) {
int j = indexOf(input, search[i], start, end);
if (j == -1) {
i++;
} else {
replaceAll(sb, input, start, j, search, replace, i + 1);
sb.append(replace[i]);
start = j + search[i].length();
}
}
sb.append(input, start, end);
}
불행히도 Java String
에는 indexOf(String str, int fromIndex, int toIndex)
방법 이 없습니다 . 나는 indexOf
그것이 정확하지 않다고 여기 에서 구현을 생략 했지만 여기에 게시 된 다양한 솔루션의 대략적인 타이밍과 함께 ideone 에서 찾을 수 있습니다 .
Java 8의 원 라이너 :
story = Pattern
.compile(String.format("(?<=%1$s)|(?=%1$s)", "foo|bar"))
.splitAsStream(story)
.map(w -> ImmutableMap.of("bar", "foo", "foo", "bar").getOrDefault(w, w))
.collect(Collectors.joining());
- Lookaround 정규 표현식 (
?<=
,?=
) : http://www.regular-expressions.info/lookaround.html - 단어에 특수 정규식 문자가 포함될 수 있으면 Pattern.quote 를 사용 하여 이스케이프 처리하십시오.
- 간결함을 위해 구아바 ImmutableMap을 사용하지만 분명히 다른 모든지도 잘 작동합니다.
다음은 일부 사용자에게 흥미로운 Java 8 스트림 가능성입니다.
String word1 = "bar";
String word2 = "foo";
String story = "Once upon a time, there was a foo and a bar.";
// Map is from untranslated word to translated word
Map<String, String> wordMap = new HashMap<>();
wordMap.put(word1, word2);
wordMap.put(word2, word1);
// Split on word boundaries so we retain whitespace.
String translated = Arrays.stream(story.split("\\b"))
.map(w -> wordMap.getOrDefault(w, w))
.collect(Collectors.joining());
System.out.println(translated);
다음은 Java 7의 동일한 알고리즘에 대한 근사치입니다.
String word1 = "bar";
String word2 = "foo";
String story = "Once upon a time, there was a foo and a bar.";
// Map is from untranslated word to translated word
Map<String, String> wordMap = new HashMap<>();
wordMap.put(word1, word2);
wordMap.put(word2, word1);
// Split on word boundaries so we retain whitespace.
StringBuilder translated = new StringBuilder();
for (String w : story.split("\\b"))
{
String tw = wordMap.get(w);
translated.append(tw != null ? tw : w);
}
System.out.println(translated);
예와 같이 공백으로 구분 된 문장에서 단어를 바꾸려면이 간단한 알고리즘을 사용할 수 있습니다.
- 공백 분할 스토리
- foo가 bar로 바뀔 경우 각 요소를 바꿉니다.
- 배열을 하나의 문자열로 다시 결합
공간 분할이 허용되지 않는 경우이 대체 알고리즘을 따를 수 있습니다. 더 긴 문자열을 먼저 사용해야합니다. 문자열이 foo와 멍청한 경우 먼저 멍청이를 사용해야합니다.
- 단어 foo로 나누기
- 배열의 각 요소를 foo로 바꿉니다.
- 마지막 요소를 제외한 각 요소 뒤에 해당 배열을 다시 추가
다음은 Map을 사용하는 덜 복잡한 답변입니다.
private static String replaceEach(String str,Map<String, String> map) {
Object[] keys = map.keySet().toArray();
for(int x = 0 ; x < keys.length ; x ++ ) {
str = str.replace((String) keys[x],"%"+x);
}
for(int x = 0 ; x < keys.length ; x ++) {
str = str.replace("%"+x,map.get(keys[x]));
}
return str;
}
그리고 방법은
Map<String, String> replaceStr = new HashMap<>();
replaceStr.put("Raffy","awesome");
replaceStr.put("awesome","Raffy");
String replaced = replaceEach("Raffy is awesome, awesome awesome is Raffy Raffy", replaceStr);
결과 : awesome은 Raffy, Raffy Raffy는 굉장합니다
대체 할 검색 문자열을 여러 번 처리 할 수있게하려면 각 검색어에서 문자열을 분할 한 다음 바꾸면 쉽게 수행 할 수 있습니다. 예를 들면 다음과 같습니다.
String regex = word1 + "|" + word2;
String[] values = Pattern.compile(regex).split(story);
String result;
foreach subStr in values
{
subStr = subStr.replace(word1, word2);
subStr = subStr.replace(word2, word1);
result += subStr;
}
다음 코드 블록으로 목표를 달성 할 수 있습니다.
String word1 = "bar";
String word2 = "foo";
String story = "Once upon a time, in a foo, there was a foo and a bar.";
story = String.format(story.replace(word1, "%1$s").replace(word2, "%2$s"),
word2, word1);
순서에 관계없이 단어를 대체합니다. 이 원칙을 다음과 같은 유틸리티 메소드로 확장 할 수 있습니다.
private static String replace(String source, String[] targets, String[] replacements) throws IllegalArgumentException {
if (source == null) {
throw new IllegalArgumentException("The parameter \"source\" cannot be null.");
}
if (targets == null || replacements == null) {
throw new IllegalArgumentException("Neither parameters \"targets\" or \"replacements\" can be null.");
}
if (targets.length == 0 || targets.length != replacements.length) {
throw new IllegalArgumentException("The parameters \"targets\" and \"replacements\" must have at least one item and have the same length.");
}
String outputMask = source;
for (int i = 0; i < targets.length; i++) {
outputMask = outputMask.replace(targets[i], "%" + (i + 1) + "$s");
}
return String.format(outputMask, (Object[])replacements);
}
다음과 같이 소비됩니다.
String story = "Once upon a time, in a foo, there was a foo and a bar.";
story = replace(story, new String[] { "bar", "foo" },
new String[] { "foo", "bar" }));
이것은 작동하며 간단합니다.
public String replaceBoth(String text, String token1, String token2) {
return text.replace(token1, "\ufdd0").replace(token2, token1).replace("\ufdd0", token2);
}
당신은 이것을 다음과 같이 사용합니다 :
replaceBoth("Once upon a time, there was a foo and a bar.", "foo", "bar");
참고 : 이것은 문자를 포함하지 않는 문자열에 의존 \ufdd0
합니다. 문자는 유니 코드에서 내부 용 으로 영구적으로 예약 한 문자입니다 ( http://www.unicode.org/faq/private_use.html 참조 ).
나는 그것이 필요하다고 생각하지 않지만, 절대 안전을 원한다면 다음을 사용할 수 있습니다.
public String replaceBoth(String text, String token1, String token2) {
if (text.contains("\ufdd0") || token1.contains("\ufdd0") || token2.contains("\ufdd0")) throw new IllegalArgumentException("Invalid character.");
return text.replace(token1, "\ufdd0").replace(token2, token1).replace("\ufdd0", token2);
}
한 번만 발생
입력에 각 스왑 가능한 문자열이 한 번만 나타나는 경우 다음을 수행 할 수 있습니다.
바꾸기를 진행하기 전에 단어의 출현 지수를 얻으십시오. 그 후 우리는 이러한 색인에서 찾은 단어 만 대체하고 모든 경우를 대체하지는 않습니다. 이 솔루션은 같은 StringBuilder
중간체를 사용 하거나 생성하지 않습니다 .String
String.replace()
한 가지 알아 두어야 할 사항 : 교체 가능한 단어의 길이가 다른 경우 첫 번째 교체 후 두 번째 색인이 첫 번째 단어가 두 번째 이전에 나타나는 경우 두 길이의 차이와 정확히 일치 할 수 있습니다. 따라서 두 번째 색인을 정렬하면 길이가 다른 단어를 바꾸는 경우에도 작동합니다.
public static String swap(String src, String s1, String s2) {
StringBuilder sb = new StringBuilder(src);
int i1 = src.indexOf(s1);
int i2 = src.indexOf(s2);
sb.replace(i1, i1 + s1.length(), s2); // Replace s1 with s2
// If s1 was before s2, idx2 might have changed after the replace
if (i1 < i2)
i2 += s2.length() - s1.length();
sb.replace(i2, i2 + s2.length(), s1); // Replace s2 with s1
return sb.toString();
}
임의의 발생 횟수 스와핑
이전의 경우와 유사하게 먼저 단어의 색인 (발생)을 수집하지만이 경우에는 단어가 아닌 각 단어의 정수 목록이 int
됩니다. 이를 위해 다음과 같은 유틸리티 방법을 사용합니다.
public static List<Integer> occurrences(String src, String s) {
List<Integer> list = new ArrayList<>();
for (int idx = 0;;)
if ((idx = src.indexOf(s, idx)) >= 0) {
list.add(idx);
idx += s.length();
} else
return list;
}
그리고 이것을 사용하여 우리는 교체 후 인덱스를 수정하지 않아도되도록 인덱스를 낮추어 단어를 다른 단어로 바꿉니다 (두 개의 교체 가능한 단어 사이를 번갈아 가야 할 수도 있음).
public static String swapAll(String src, String s1, String s2) {
List<Integer> l1 = occurrences(src, s1), l2 = occurrences(src, s2);
StringBuilder sb = new StringBuilder(src);
// Replace occurrences by decreasing index, alternating between s1 and s2
for (int i1 = l1.size() - 1, i2 = l2.size() - 1; i1 >= 0 || i2 >= 0;) {
int idx1 = i1 < 0 ? -1 : l1.get(i1);
int idx2 = i2 < 0 ? -1 : l2.get(i2);
if (idx1 > idx2) { // Replace s1 with s2
sb.replace(idx1, idx1 + s1.length(), s2);
i1--;
} else { // Replace s2 with s1
sb.replace(idx2, idx2 + s2.length(), s1);
i2--;
}
}
return sb.toString();
}
다음을 사용하여이를 수행하는 방법을 쉽게 작성할 수 있습니다 String.regionMatches
.
public static String simultaneousReplace(String subject, String... pairs) {
if (pairs.length % 2 != 0) throw new IllegalArgumentException(
"Strings to find and replace are not paired.");
StringBuilder sb = new StringBuilder();
outer:
for (int i = 0; i < subject.length(); i++) {
for (int j = 0; j < pairs.length; j += 2) {
String find = pairs[j];
if (subject.regionMatches(i, find, 0, find.length())) {
sb.append(pairs[j + 1]);
i += find.length() - 1;
continue outer;
}
}
sb.append(subject.charAt(i));
}
return sb.toString();
}
테스트 :
String s = "There are three cats and two dogs.";
s = simultaneousReplace(s,
"cats", "dogs",
"dogs", "budgies");
System.out.println(s);
산출:
3 마리의 개와 2 마리의 budgie가 있습니다.
즉시 명백하지는 않지만 이와 같은 기능은 여전히 교체가 지정된 순서에 따라 달라질 수 있습니다. 치다:
String truth = "Java is to JavaScript";
truth += " as " + simultaneousReplace(truth,
"JavaScript", "Hamster",
"Java", "Ham");
System.out.println(truth);
산출:
Ham은 Hamster와 마찬가지로 Java는 JavaScript를
그러나 교체를 역전하십시오.
truth += " as " + simultaneousReplace(truth,
"Java", "Ham",
"JavaScript", "Hamster");
산출:
Ham은 HamScript와 마찬가지로 Java는 JavaScript를
죄송합니다! :)
따라서 PHP 함수 와 같이 가장 긴 일치 항목 을 찾는 것이 유용한 경우가 strtr
있습니다. 이 버전의 메소드는 다음을 수행합니다.
public static String simultaneousReplace(String subject, String... pairs) {
if (pairs.length % 2 != 0) throw new IllegalArgumentException(
"Strings to find and replace are not paired.");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < subject.length(); i++) {
int longestMatchIndex = -1;
int longestMatchLength = -1;
for (int j = 0; j < pairs.length; j += 2) {
String find = pairs[j];
if (subject.regionMatches(i, find, 0, find.length())) {
if (find.length() > longestMatchLength) {
longestMatchIndex = j;
longestMatchLength = find.length();
}
}
}
if (longestMatchIndex >= 0) {
sb.append(pairs[longestMatchIndex + 1]);
i += longestMatchLength - 1;
} else {
sb.append(subject.charAt(i));
}
}
return sb.toString();
}
위의 방법은 대소 문자를 구분합니다. 대소 문자를 구분하지 않는 버전이 필요한 경우 매개 변수를 String.regionMatches
사용할 수 있으므로 위의 내용을 쉽게 수정할 수 있습니다 ignoreCase
.
종속성을 원하지 않으면 일회성 변경 만 허용하는 배열을 사용하면됩니다. 이것은 가장 효율적인 솔루션은 아니지만 작동해야합니다.
public String replace(String sentence, String[]... replace){
String[] words = sentence.split("\\s+");
int[] lock = new int[words.length];
StringBuilder out = new StringBuilder();
for (int i = 0; i < words.length; i++) {
for(String[] r : replace){
if(words[i].contains(r[0]) && lock[i] == 0){
words[i] = words[i].replace(r[0], r[1]);
lock[i] = 1;
}
}
out.append((i < (words.length - 1) ? words[i] + " " : words[i]));
}
return out.toString();
}
그런 다음 일을해야했습니다.
String story = "Once upon a time, there was a foo and a bar.";
String[] a = {"foo", "bar"};
String[] b = {"bar", "foo"};
String[] c = {"there", "Pocahontas"};
story = replace(story, a, b, c);
System.out.println(story); // Once upon a time, Pocahontas was a bar and a foo.
입력에 대해 여러 검색 바꾸기 작업을 수행하고 있습니다. 대체 문자열에 검색 문자열이 포함되어 있으면 원하지 않는 결과가 발생합니다. foo-> bar, bar-foo 예제를 고려하십시오. 각 반복에 대한 결과는 다음과 같습니다.
- 옛날 옛적에 foo와 술집이있었습니다. (입력)
- 옛날 옛적에 바와 바가있었습니다. (foo-> 바)
- 옛날 옛적에 foo와 foo가있었습니다. (bar-> foo, 출력)
돌아 가지 않고 한 번의 반복으로 교체를 수행해야합니다. 무차별 대입 솔루션은 다음과 같습니다.
- 일치하는 것을 찾을 때까지 현재 위치에서 입력을 검색하여 여러 검색 문자열을 종료하십시오.
- 일치하는 검색 문자열을 해당하는 대체 문자열로 바꿉니다.
- 교체 된 문자열 다음에 현재 위치를 다음 문자로 설정
- 반복
같은 함수는 String.indexOfAny(String[]) -> int[]{index, whichString}
유용 할 것이다. 다음은 가장 효율적인 예는 아닙니다.
private static String replaceEach(String str, String[] searchWords, String[] replaceWords) {
String ret = "";
while (str.length() > 0) {
int i;
for (i = 0; i < searchWords.length; i++) {
String search = searchWords[i];
String replace = replaceWords[i];
if (str.startsWith(search)) {
ret += replace;
str = str.substring(search.length());
break;
}
}
if (i == searchWords.length) {
ret += str.substring(0, 1);
str = str.substring(1);
}
}
return ret;
}
일부 테스트 :
System.out.println(replaceEach(
"Once upon a time, there was a foo and a bar.",
new String[]{"foo", "bar"},
new String[]{"bar", "foo"}
));
// Once upon a time, there was a bar and a foo.
System.out.println(replaceEach(
"a p",
new String[]{"a", "p"},
new String[]{"apple", "pear"}
));
// apple pear
System.out.println(replaceEach(
"ABCDE",
new String[]{"A", "B", "C", "D", "E"},
new String[]{"B", "C", "E", "E", "F"}
));
// BCEEF
System.out.println(replaceEach(
"ABCDEF",
new String[]{"ABCDEF", "ABC", "DEF"},
new String[]{"XXXXXX", "YYY", "ZZZ"}
));
// XXXXXX
// note the order of search strings, longer strings should be placed first
// in order to make the replacement greedy
당신은 항상 당신이 문자열의 다른 곳에 나타나지 않을 것이라고 확신하는 단어로 바꿀 수 있습니다.
String word1 = "bar";
String word2 = "foo";
String story = "Once upon a time, there was a foo and a bar."
story = story.replace("foo", "StringYouAreSureWillNeverOccur").replace("bar", "word2").replace("StringYouAreSureWillNeverOccur", "word1");
"StringYouAreSureWillNeverOccur"
발생 하면 제대로 작동 하지 않습니다.
StringBuilder 사용을 고려하십시오
그런 다음 각 문자열을 시작해야하는 색인을 저장하십시오. 각 위치에 자리 표시 자 문자를 사용하는 경우이를 제거하고 사용자 문자열을 삽입하십시오. 그런 다음 문자열 길이를 시작 위치에 추가하여 끝 위치를 매핑 할 수 있습니다.
String firstString = "???";
String secondString = "???"
StringBuilder story = new StringBuilder("One upon a time, there was a "
+ firstString
+ " and a "
+ secondString);
int firstWord = 30;
int secondWord = firstWord + firstString.length() + 7;
story.replace(firstWord, firstWord + firstString.length(), userStringOne);
story.replace(secondWord, secondWord + secondString.length(), userStringTwo);
firstString = userStringOne;
secondString = userStringTwo;
return story;
내가 공유 할 수있는 것은 내 자신의 방법입니다.
임시 String temp = "<?>";
또는String.Format();
이것은 c # - "아이디어 만, 정확한 답변 아님"을 통해 콘솔 응용 프로그램에서 작성된 예제 코드입니다 .
static void Main(string[] args)
{
String[] word1 = {"foo", "Once"};
String[] word2 = {"bar", "time"};
String story = "Once upon a time, there was a foo and a bar.";
story = Switcher(story,word1,word2);
Console.WriteLine(story);
Console.Read();
}
// Using a temporary string.
static string Switcher(string text, string[] target, string[] value)
{
string temp = "<?>";
if (target.Length == value.Length)
{
for (int i = 0; i < target.Length; i++)
{
text = text.Replace(target[i], temp);
text = text.Replace(value[i], target[i]);
text = text.Replace(temp, value[i]);
}
}
return text;
}
또는 당신은 또한 사용할 수 있습니다 String.Format();
static string Switcher(string text, string[] target, string[] value)
{
if (target.Length == value.Length)
{
for (int i = 0; i < target.Length; i++)
{
text = text.Replace(target[i], "{0}").Replace(value[i], "{1}");
text = String.Format(text, value[i], target[i]);
}
}
return text;
}
산출: time upon a Once, there was a bar and a foo.
다음은 단어 기반의 내 버전입니다.
class TextReplace
{
public static void replaceAll (String text, String [] lookup,
String [] replacement, String delimiter)
{
String [] words = text.split(delimiter);
for (int i = 0; i < words.length; i++)
{
int j = find(lookup, words[i]);
if (j >= 0) words[i] = replacement[j];
}
text = StringUtils.join(words, delimiter);
}
public static int find (String [] array, String key)
{
for (int i = 0; i < array.length; i++)
if (array[i].equals(key))
return i;
return (-1);
}
}
String word1 = "bar";
String word2 = "foo";
String story = "Once upon a time, there was a foo and a bar."
조금 까다로운 방법이지만 더 확인해야합니다.
1. 문자열을 문자형 배열로 변환
String temp[] = story.split(" ");//assume there is only spaces.
온도에 2.loop 및 교체 foo
와 함께 bar
와 bar
함께 foo
다시 교체 문자열을 점점 더 기회가 없기 때문에.
짧은 대답은 ...
String word1 = "bar";
String word2 = "foo";
String story = "Once upon a time, there was a foo and a bar.";
story = story.replace("foo", "@"+ word1).replace("bar", word2).replace("@" + word2, word1);
System.out.println(story);
여기에 있는 대답을 사용하여 바꾸려는 모든 문자열을 찾을 수 있습니다.
예를 들어 위의 SO 답변에서 코드를 실행하십시오. 두 개의 색인 테이블을 작성하십시오 (bar와 foo는 문자열에 한 번만 표시되지 않음).이 테이블을 사용하여 문자열에서 대체 할 수 있습니다.
이제 특정 색인 위치를 대체하기 위해 다음을 사용할 수 있습니다.
public static String replaceStringAt(String s, int pos, String c) {
return s.substring(0,pos) + c + s.substring(pos+1);
}
반면 pos
문자열은 위에서 인용 한 색인 테이블에서 시작하는 색인입니다. 각각에 대해 두 개의 인덱스 테이블을 생성했다고 가정하겠습니다. 의 그들을 부르 자 indexBar
와 indexFoo
.
이제 교체 할 때마다 교체 할 루프마다 하나씩 두 개의 루프를 실행할 수 있습니다.
for(int i=0;i<indexBar.Count();i++)
replaceStringAt(originalString,indexBar[i],newString);
마찬가지로 다른 루프입니다 indexFoo
.
이것은 다른 답변만큼 효율적이지 않을 수 있지만지도 또는 다른 것들보다 이해하기가 더 간단합니다.
이렇게하면 항상 원하는 결과를 얻을 수 있고 각 문자열이 여러 번 나타날 수 있습니다. 각 발생의 색인을 저장하는 한.
또한이 대답은 재귀 나 외부 종속성이 필요하지 않습니다. 복잡성에 관한 한 그것은 적절하게 O (n squared)이며, n은 두 단어의 총합입니다.
이 코드를 개발하여 문제를 해결할 수 있습니다.
public static String change(String s,String s1, String s2) {
int length = s.length();
int x1 = s1.length();
int x2 = s2.length();
int x12 = s.indexOf(s1);
int x22 = s.indexOf(s2);
String s3=s.substring(0, x12);
String s4 =s.substring(x12+3, x22);
s=s3+s2+s4+s1;
return s;
}
주요 용도 change(story,word2,word1).
String word1 = "bar";
String word2 = "foo";
String story = "Once upon a time, there was a foo and a bar."
story = story.replace("foo", "<foo />");
story = story.replace("bar", "<bar />");
story = story.replace("<foo />", word1);
story = story.replace("<bar />", word2);
'IT박스' 카테고리의 다른 글
삼항 연산자가 R에 있습니까? (0) | 2020.06.03 |
---|---|
Git 브랜치에서 특정 파일을 병합하는 방법 (0) | 2020.06.03 |
로그를 역순으로 git하는 방법? (0) | 2020.06.03 |
VBA를 사용하지 않고 Excel에서 리버스 문자열 검색을 수행하려면 어떻게해야합니까? (0) | 2020.06.03 |
Chrome에서 console.log를 파일로 저장 (0) | 2020.06.03 |