ฉันจะแทนที่สองสายในวิธีที่ไม่จบลงแทนที่สายอื่นได้อย่างไร


162

สมมติว่าฉันมีรหัสต่อไปนี้:

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."ฉันจะทำให้สำเร็จได้อย่างไร


7
1 มีแน่นอนควรจะเป็นฟังก์ชั่นบางอย่างswap(String s1, String s2, String s3)ที่สัญญาทั้งหมดที่เกิดขึ้นของs2ด้วยs3และในทางกลับกัน
Ryan

เราสามารถสมมติได้ว่ามีคำศัพท์ที่ถอดเปลี่ยนได้เพียงคำเดียวในอินพุตหรือไม่
icza

14
มุมกรณี: เราคาดหวังอะไรเป็นเอาท์พุทเมื่อแลกเปลี่ยน "ab" และ "ba" ใน "ababababababa"
Hagen von Eitzen

1
คุณมีวิธีแก้ปัญหาที่ดีด้านล่าง แต่คุณเข้าใจไหมว่าทำไมแนวทางของคุณถึงใช้งานไม่ได้ ก่อนอื่นคุณมี "มีแฟนและบาร์อยู่" หลังจากแทนที่ครั้งแรก ("foo" -> "bar") คุณมี "มีแถบและแถบ" ตอนนี้คุณมี "bar" เกิดขึ้น 2 ครั้งดังนั้นการแทนที่ครั้งที่สองของคุณไม่ได้ทำตามที่คุณคาดหวัง - ไม่มีทางรู้ว่าคุณต้องการแทนที่สิ่งที่คุณไม่ได้แทนที่ครั้งล่าสุด @HagenvonEitzen น่าสนใจ ฉันคาดหวังว่าวิธีแก้ปัญหาการทำงานเพื่อจับคู่และแทนที่สตริงแรกที่พบแล้วทำซ้ำจากส่วนท้ายของส่วนแทนที่
DeveloperInDevelopment

1
วิธีแก้ปัญหาของ Jeroen คือสิ่งที่ฉันใช้บ่อยในโปรแกรมแก้ไขข้อความเมื่อฉันต้องเปลี่ยนชื่อเป็นจำนวนมาก มันง่ายและเข้าใจง่ายไม่ต้องใช้ห้องสมุดพิเศษและสามารถเข้าใจผิดได้ด้วยความคิดเล็กน้อย
เลียร้อน

คำตอบ:


88

ใช้replaceEach()วิธีการจากApache Commons StringUtils :

StringUtils.replaceEach(story, new String[]{"foo", "bar"}, new String[]{"bar", "foo"})

2
ความคิดใด ๆ สิ่งที่ replaceEach ทำภายในอย่างแน่นอน?
Marek

3
@Marek เป็นไปได้มากว่าฟังก์ชั่นจะทำการค้นหาและจัดทำดัชนีแต่ละรายการที่พบจากนั้นแทนที่ทั้งหมดเมื่อมีการทำดัชนีทั้งหมด

16
คุณสามารถหาแหล่งที่มาของสิ่งนี้ได้ที่นี่รอบ ๆ บรรทัดที่ 4684
Jeroen Vannevel

มันเป็นเรื่องที่น่าเสียดายที่ไม่มีการใช้งานเมื่อnullผ่านไป
rightfold

87

คุณใช้ค่ากลาง (ซึ่งยังไม่ปรากฏในประโยค)

story = story.replace("foo", "lala");
story = story.replace("bar", "foo");
story = story.replace("lala", "bar");

เป็นการตอบสนองต่อการวิจารณ์: หากคุณใช้สตริงที่มีขนาดใหญ่พอเช่นzq515sqdqs5d5sq1dqs4d1q5dqqé "& é5d4sqjshsjddjhodfqsqc, nvùq ^ µù;และการใช้งานที่เป็นไปได้ยากที่จะจุดที่ฉันจะไม่ได้อภิปรายมัน ที่ผู้ใช้จะเคยป้อนสิ่งนี้วิธีเดียวที่จะรู้ว่าผู้ใช้จะรู้หรือไม่โดยการรู้ซอร์สโค้ดและ ณ จุดนั้นคุณก็มีความกังวลอีกระดับ

ใช่อาจมีวิธีการ regex แฟนซี ฉันชอบบางสิ่งที่สามารถอ่านได้ซึ่งฉันรู้ว่าจะไม่ทำให้ฉันผิดหวัง

ยังคงคำแนะนำที่ยอดเยี่ยมที่ได้รับจาก@David Conrad ในความคิดเห็น :

อย่าใช้สตริงที่เลือกอย่างชาญฉลาด (อย่างโง่เขลา) ที่จะไม่เกิดขึ้น ใช้ตัวอักษรจาก Unicode Private Use Area, U + E000..U + F8FF ลบอักขระดังกล่าวออกก่อนเนื่องจากไม่ควรอยู่ในอินพุตอย่างถูกต้อง (มีเพียงความหมายเฉพาะแอปพลิเคชันภายในบางแอปพลิเคชัน) จากนั้นใช้เป็นตัวยึดตำแหน่งเมื่อแทนที่


4
@arshajii ฉันเดาว่าขึ้นอยู่กับคำนิยามของคุณว่า "ดีกว่า" ... ถ้ามันใช้งานได้และเป็นที่ยอมรับได้ให้ไปที่ภารกิจการเขียนโปรแกรมถัดไปและปรับปรุงในภายหลังในระหว่างการสร้างใหม่
Matt Coubrough

24
เห็นได้ชัดว่า "ลาลา" เป็นเพียงตัวอย่าง ในการผลิตคุณควรใช้ " zq515sqdqs5d5sq1dqs4d1q5dqqé" & é & € sdq: d:;) àçàçlala ".
Jeroen Vannevel

81
อย่าใช้สตริงที่เลือกอย่างชาญฉลาด (อย่างโง่เขลา) ที่จะไม่เกิดขึ้น ใช้ตัวอักษรจาก Unicode Private Use Area, U + E000..U + F8FF ลบอักขระดังกล่าวออกก่อนเนื่องจากไม่ควรอยู่ในอินพุตอย่างถูกต้อง (มีเพียงความหมายเฉพาะแอปพลิเคชันภายในบางแอปพลิเคชัน) จากนั้นใช้เป็นตัวยึดตำแหน่งเมื่อแทนที่
David Conrad

22
ที่จริงแล้วหลังจากอ่านUnicode FAQ บนมันฉันคิดว่าตัวละครที่ไม่ใช่ในช่วง U + FDD0 .. U + FDEF จะเป็นตัวเลือกที่ดียิ่งขึ้น
David Conrad

6
@Taemyr แน่นอน แต่มีคนที่ต้องฆ่าเชื้อการป้อนข้อมูลใช่มั้ย ฉันคาดหวังว่าฟังก์ชั่นการเปลี่ยนสตริงทำงานได้กับสตริงทั้งหมด แต่ฟังก์ชั่นนี้แบ่งสำหรับอินพุตที่ไม่ปลอดภัย
Navin

33

คุณสามารถลองสิ่งนี้โดยใช้Matcher#appendReplacementและ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());
กาลครั้งหนึ่งนานมาแล้วมีบาร์และฟู

2
ทำงานนี้ถ้าfoo, barและstoryทุกคนมีค่าไม่ทราบ?
สตีเฟ่น P

1
@StephenP ฉันได้เขียนโค้ด"foo"และ"bar"แทนที่สตริงอย่างที่ OP มีอยู่ในโค้ดของเขา แต่วิธีการแบบเดียวกันจะใช้ได้ดีแม้ว่าจะไม่ทราบค่าเหล่านั้น (คุณต้องใช้if/ else ifแทนที่จะเป็นswitchภายในwhile-loop)
arshajii

6
คุณต้องระวังในการสร้าง regex Pattern.quoteจะมาในสะดวกหรือและ\Q \E
David Conrad

1
@arshajii - อ๋อพิสูจน์ด้วยตัวเองว่าเป็น "swapThese" วิธีการใช้ word1, word2 และเรื่องราวเป็นพารามิเตอร์ +1
Stephen P

4
แม้แต่คนที่สะอาดกว่าก็ควรใช้รูปแบบ(foo)|(bar)จากนั้นตรวจสอบm.group(1) != nullเพื่อหลีกเลี่ยงการทำซ้ำคำที่ตรงกัน
Jörn Horstmann

32

นี่ไม่ใช่ปัญหาง่าย และยิ่งคุณมีพารามิเตอร์แทนที่การค้นหามากเท่าไหร่ก็ยิ่งได้รับมากขึ้นเท่านั้น คุณมีหลายตัวเลือกกระจัดกระจายอยู่บนจานสีที่สวยงามน่าเกลียดและสิ้นเปลืองอย่างมีประสิทธิภาพ:

  • ใช้StringUtils.replaceEachจาก Apache Commons ตามที่แนะนำ@AlanHay นี่เป็นตัวเลือกที่ดีถ้าคุณมีอิสระในการเพิ่มการอ้างอิงใหม่ในโครงการของคุณ คุณอาจโชคดี: การพึ่งพานั้นอาจรวมอยู่ในโครงการของคุณแล้ว

  • ใช้ตัวยึดตำแหน่งชั่วคราวตามที่@Jeroenแนะนำและดำเนินการแทนที่ใน 2 ขั้นตอน:

    1. แทนที่รูปแบบการค้นหาทั้งหมดด้วยแท็กที่ไม่ซ้ำกันซึ่งไม่มีอยู่ในข้อความต้นฉบับ
    2. แทนที่ตัวยึดตำแหน่งด้วยการเปลี่ยนเป้าหมายจริง

    นี่ไม่ใช่วิธีการที่ยอดเยี่ยมด้วยเหตุผลหลายประการ: จำเป็นต้องตรวจสอบให้แน่ใจว่าแท็กที่ใช้ในขั้นตอนแรกนั้นมีความเป็นเอกลักษณ์จริงๆ มันทำการดำเนินการเปลี่ยนสายอักขระมากกว่าที่จำเป็นจริงๆ

  • สร้าง regex จากทุกรูปแบบและใช้วิธีการที่มีMatcherและStringBufferแนะนำโดย@arshajii นี้ไม่ได้น่ากลัว แต่ไม่ว่าดีอย่างใดอย่างหนึ่งกับการสร้าง regex เป็นชนิดของ hackish และมันเกี่ยวข้องกับการที่ไปออกของแฟชั่นในขณะที่ที่ผ่านมาในความโปรดปรานของStringBufferStringBuilder

  • ใช้โซลูชันแบบเรียกซ้ำที่เสนอโดย@mjolkaโดยแยกสตริงที่รูปแบบที่ตรงกันและเรียกใช้ซ้ำในส่วนที่เหลือ นี่เป็นทางออกที่ดีกะทัดรัดและสวยงามมาก จุดอ่อนของมันคือการดำเนินการสตริงย่อยและการต่อข้อมูลจำนวนมากและขีด จำกัด ขนาดสแต็กที่ใช้กับโซลูชันแบบเรียกซ้ำทั้งหมด

  • แยกข้อความเป็นคำและใช้ Java 8 สตรีมเพื่อดำเนินการแทนที่อย่างหรูหราตามที่@ msandifordแนะนำ แต่แน่นอนว่าจะทำงานได้ก็ต่อเมื่อคุณตกลงแยกขอบเขตคำซึ่งไม่เหมาะสำหรับการแก้ปัญหาทั่วไป

นี่คือรุ่นของฉันอยู่บนพื้นฐานของความคิดที่ยืมมาจากการดำเนินงานของ 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"})
    );
}

21

ค้นหาคำแรกที่จะถูกแทนที่ หากอยู่ในสตริงให้ทำการหักส่วนของสตริงก่อนที่จะเกิดขึ้นและในส่วนของสตริงหลังจากที่เกิดขึ้น

มิฉะนั้นให้ดำเนินการต่อด้วยคำถัดไปเพื่อแทนที่

การนำไปปฏิบัติที่ไร้เดียงสาอาจมีลักษณะเช่นนี้

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พร้อมกับกำหนดเวลาคร่าวๆของโซลูชันต่างๆที่โพสต์ที่นี่


2
แม้ว่าการใช้ห้องสมุดที่มีอยู่เช่น apache ทั่วไปสำหรับสิ่งนี้ไม่ต้องสงสัยเลยว่าวิธีที่ง่ายที่สุดในการแก้ปัญหาที่พบบ่อยนี้เป็นเรื่องธรรมดา แต่คุณได้แสดงให้เห็นถึงการนำไปใช้งานที่ทำงานได้ในบางส่วนของคำ (ปัจจุบัน) คำตอบที่โหวตให้สูงกว่า +1
Buhb

สวยงาม แต่กระทบกับพื้นเมื่อมีการป้อนไฟล์ 100 mb
Christophe De Troyer

12

หนึ่งซับใน 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
  • หากคำสามารถมีอักขระพิเศษ regex ใช้Pattern.quoteเพื่อหลีกเลี่ยง
  • ฉันใช้ guava ImmutableMap เพื่อความกระชับ แต่เห็นได้ชัดว่าแผนที่อื่น ๆ ก็สามารถทำงานได้เช่นกัน

11

นี่เป็นความเป็นไปได้ของ 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);

10
นี่เป็นคำแนะนำที่ดีเมื่อสิ่งที่คุณต้องการแทนที่เป็นคำที่แท้จริงคั่นด้วยช่องว่าง (หรือคล้ายกัน) แต่สิ่งนี้จะไม่ทำงานสำหรับการแทนที่สตริงย่อยของคำ
Simon Forsberg

+1 สำหรับสตรีม Java8 น่าเสียดายที่ต้องมีตัวคั่น
Navin

6

หากคุณต้องการแทนที่คำในประโยคที่คั่นด้วยช่องว่างตามที่แสดงในตัวอย่างของคุณคุณสามารถใช้อัลกอริทึมแบบง่าย ๆ นี้ได้

  1. แยกเรื่องบนพื้นที่สีขาว
  2. แทนที่แต่ละองค์ประกอบหาก foo เปลี่ยนเป็น bar และ Vice varsa
  3. เข้าร่วมอาร์เรย์กลับเข้าไปในสตริงเดียว

หากการแยกพื้นที่ไม่เป็นที่ยอมรับเราสามารถทำตามอัลกอริธึมทางเลือกนี้ได้ คุณต้องใช้สตริงที่ยาวกว่าก่อน หาก stringes เป็น foo and fool คุณต้องใช้ fool ก่อนแล้วจึง foo

  1. แยกคำว่าฟู
  2. แทนที่แถบด้วย foo แต่ละองค์ประกอบของอาร์เรย์
  3. เข้าร่วมแถวนั้นกลับเพิ่มบาร์หลังจากแต่ละองค์ประกอบยกเว้นที่ผ่านมา

1
นี่คือสิ่งที่ฉันคิดที่จะแนะนำด้วย แม้ว่ามันจะเพิ่มข้อ จำกัด ที่ข้อความเป็นคำที่ล้อมรอบด้วยช่องว่าง :)
นักพัฒนา Marius Žilėnas

@ MariusŽilėnasฉันได้เพิ่มอัลกอริธึมทางเลือก
fastcodejava

5

นี่คือคำตอบที่ซับซ้อนน้อยกว่าการใช้แผนที่

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 is Raffy, Raffy Raffy นั้นยอดเยี่ยมมาก


1
การทำงานreplaced.replaceAll("Raffy", "Barney");หลังจากนี้จะทำให้มันเป็น Legen ... รอให้มัน; Dary !!!
Keale

3

หากคุณต้องการที่จะจัดการกับสตริงการค้นหาหลายรายการที่จะถูกแทนที่คุณสามารถทำได้อย่างง่ายดายโดยแยกสตริงในแต่ละข้อความค้นหาจากนั้นแทนที่มัน นี่คือตัวอย่าง:

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

3

คุณสามารถบรรลุเป้าหมายของคุณด้วยการบล็อกรหัสต่อไปนี้:

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

3

งานนี้และง่าย:

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

หมายเหตุ: สิ่งนี้นับจาก Strings ที่ไม่มีอักขระ\ufdd0ซึ่งเป็นอักขระที่สงวนไว้อย่างถาวรสำหรับการใช้งานภายในโดย Unicode (ดู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);
    }

3

การแลกเปลี่ยนรายการเดียวที่เกิดขึ้น

หากมีการเกิดขึ้นเพียงครั้งเดียวของแต่ละสตริงที่สลับได้ในอินพุตคุณสามารถทำสิ่งต่อไปนี้:

ก่อนที่จะดำเนินการแทนที่ใด ๆ รับดัชนีของการเกิดขึ้นของคำ หลังจากนั้นเราจะแทนที่คำที่พบในดัชนีเหล่านี้เท่านั้นและไม่ใช่ทั้งหมดที่เกิดขึ้น นี้ใช้วิธีการแก้ปัญหาStringBuilderและไม่ได้ผลิตกลางเหมือนStringString.replace()

สิ่งหนึ่งที่ควรทราบ: หากคำที่สลับได้มีความยาวต่างกันหลังจากที่ดัชนีแรกแทนที่ดัชนีที่สองอาจเปลี่ยนไป (หากคำที่ 1 เกิดขึ้นก่อนที่ 2) ตรงกับความแตกต่างของ 2 ดังนั้นการจัดดัชนีที่สองจะช่วยให้มั่นใจได้ว่างานนี้แม้ว่าเราจะสลับคำที่มีความยาวต่างกัน

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

และการใช้สิ่งนี้เราจะแทนที่คำด้วยอีกคำหนึ่งโดยการลดดัชนี (ซึ่งอาจต้องสลับกันระหว่างคำที่สลับได้ 2 คำ) เพื่อที่เราจะได้ไม่ต้องแก้ไขดัชนีหลังจากแทนที่:

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

ฉันไม่แน่ใจว่า java จัดการยูนิโค้ดอย่างไร แต่โค้ด C # ที่เทียบเท่ากันนี้จะไม่ถูกต้อง ปัญหาคือสตริงย่อยที่indexOfตรงกันอาจมีความยาวไม่เท่ากันกับสตริงค้นหาเนื่องจากความเหมือนกันของสตริงเทียบเท่ายูนิโค้ด
CodesInChaos

@CodesInChaos มันทำงานได้อย่างไม่มีที่ติใน Java เพราะ Java Stringเป็นอาร์เรย์อักขระและไม่ใช่อาร์เรย์ไบต์ วิธีการทั้งหมดStringและStringBuilderดำเนินการกับตัวละครที่ไม่ได้อยู่ในไบต์ซึ่งเป็น "การเข้ารหัสฟรี" ดังนั้นการindexOfจับคู่จึงมีความยาว (ตัวอักษร) เหมือนกับสตริงการค้นหา
icza

ใน C # และ java สตริงเป็นชุดของหน่วยรหัส UTF-16 ปัญหาคือมีลำดับของ codepoints ที่แตกต่างกันซึ่ง Unicode ถือว่าเทียบเท่ากัน ยกตัวอย่างเช่นäสามารถเข้ารหัสเป็นจุดโค้ดเดียวหรือเป็นตามมาด้วยการรวมa ¨นอกจากนี้ยังมี codepoints บางตัวที่ถูกละเว้นเช่นตัวเชื่อมความกว้างศูนย์ (ไม่ใช่) ไม่สำคัญว่าสตริงนั้นประกอบด้วยไบต์ตัวอักษรหรืออะไรก็ตาม แต่indexOfใช้กฎการเปรียบเทียบ มันอาจใช้หน่วยโค้ดเพียงแค่การเปรียบเทียบโค้ดหน่วย ("Ordinal") หรืออาจใช้การเทียบเท่ายูนิโค้ด ฉันไม่รู้ว่าจาวาตัวใดที่เลือก
CodesInChaos

ตัวอย่างเช่น"ab\u00ADc".IndexOf("bc")คืนค่าเป็น1. net ที่จับคู่สตริงอักขระสองตัวbcกับสตริงอักขระสามตัว
CodesInChaos

1
@CodesInChaos ฉันเห็นสิ่งที่คุณหมายถึงตอนนี้ ใน Java "ab\u00ADc".indexOf("bc")ผลตอบแทน-1ซึ่งหมายความว่าไม่พบใน"bc" "ab\u00ADc"ดังนั้นจึงยังคงเห็นได้ว่าใน Java อัลกอริทึมดังกล่าวใช้งาน indexOf()ได้การจับคู่มีความยาว (ตัวอักษร) เหมือนกันกับสตริงการค้นหาและindexOf()รายงานจะตรงเท่านั้นหากการจับคู่แบบเหมา
icza

2

การเขียนวิธีการทำได้ง่าย ๆ โดยใช้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);

เอาท์พุท:

มีสุนัขสามตัวและสองดอกตูม

ไม่ชัดเจนในทันที แต่ฟังก์ชันเช่นนี้ยังสามารถขึ้นอยู่กับลำดับที่ระบุการเปลี่ยนได้ พิจารณา:

String truth = "Java is to JavaScript";
truth += " as " + simultaneousReplace(truth,
    "JavaScript", "Hamster",
    "Java", "Ham");
System.out.println(truth);

เอาท์พุท:

Java ใช้จาวาสคริปต์เนื่องจากแฮมคือแฮมสเตอร์

แต่กลับรายการทดแทน:

truth += " as " + simultaneousReplace(truth,
    "Java", "Ham",
    "JavaScript", "Hamster");

เอาท์พุท:

จาวาใช้จาวาสคริปต์เนื่องจากแฮมเป็นจาวาสคริปต์

อ๊ะ! :)

ดังนั้นบางครั้งมันก็มีประโยชน์ที่จะตรวจสอบให้แน่ใจว่าค้นหาคู่ที่ยาวที่สุด (เช่นstrtrฟังก์ชั่นของ PHP ทำ) วิธีการในรุ่นนี้จะทำเช่นนั้น:

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พารามิเตอร์ได้


2

หากคุณไม่ต้องการการพึ่งพาใด ๆ คุณสามารถใช้อาร์เรย์ที่อนุญาตให้เปลี่ยนแปลงเพียงครั้งเดียวเท่านั้น นี่ไม่ใช่วิธีที่มีประสิทธิภาพที่สุด แต่ควรใช้งานได้

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.

2

คุณกำลังดำเนินการค้นหาแทนที่หลายรายการในอินพุต สิ่งนี้จะสร้างผลลัพธ์ที่ไม่พึงประสงค์เมื่อสตริงการแทนที่มีสตริงการค้นหา พิจารณา foo-> bar ตัวอย่าง bar-foo ต่อไปนี้เป็นผลลัพธ์สำหรับการวนซ้ำแต่ละครั้ง:

  1. กาลครั้งหนึ่งมีทั้งบาร์และบาร์ (input)
  2. กาลครั้งหนึ่งมีบาร์และบาร์หนึ่งครั้ง (foo-> บาร์)
  3. กาลครั้งหนึ่งนานมาแล้วมีทั้งฟูและฟู (bar-> foo, output)

คุณต้องทำการแทนที่ในหนึ่งรอบโดยไม่ต้องย้อนกลับ วิธีการแก้ปัญหากำลังดุร้ายเป็นดังนี้:

  1. ค้นหาอินพุตจากตำแหน่งปัจจุบันเพื่อสิ้นสุดสตริงการค้นหาหลายรายการจนกว่าจะพบการจับคู่
  2. แทนที่สตริงการค้นหาที่ตรงกันด้วยสตริงการแทนที่ที่สอดคล้องกัน
  3. ตั้งตำแหน่งปัจจุบันไปที่ตัวละครต่อไปหลังจากสตริงแทนที่
  4. ทำซ้ำ

ฟังก์ชั่นเช่น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

การสาธิตใน IDEONE การ
สาธิตบน IDEONE, รหัสอื่น


1

คุณสามารถแทนที่ด้วยคำที่คุณแน่ใจว่าจะปรากฏที่ใดก็ได้ในสตริงจากนั้นทำการแทนที่ที่สองในภายหลัง:

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"เกิดขึ้น


5
ใช้ตัวอักษรจาก Unicode Private Use Area, U + E000 .. U + F8FF สร้าง StringThatCannotEverOccur คุณสามารถกรองออกได้ล่วงหน้าเนื่องจากไม่ควรมีอยู่ในอินพุต
David Conrad

หรือ U + FDD0 .. U + FDEF, "Noncharacters" ซึ่งสงวนไว้สำหรับใช้ภายใน
David Conrad

1

พิจารณาใช้ 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;

1

สิ่งที่ฉันสามารถแบ่งปันได้ก็คือวิธีการของฉันเอง

คุณสามารถใช้งานชั่วคราวString temp = "<?>";หรือString.Format();

นี่คือรหัสตัวอย่างของฉันที่สร้างขึ้นในแอปพลิเคชันคอนโซลผ่าน - "ความคิดเท่านั้นไม่ได้มีคำตอบที่แน่นอน"

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.


มันค่อนข้างแฮ็ค คุณจะทำอย่างไรถ้าเขาต้องการแทนที่ "_"
Pier-Alexandre Bouchard

@ ท่าเรือ-AlexandreBouchard ในวิธีการที่ผมเปลี่ยนค่าของtempจากเข้า"_" <?>แต่ถ้าจำเป็นสิ่งที่เขาสามารถทำได้คือการเพิ่มพารามิเตอร์อื่นให้กับวิธีการที่จะเปลี่ยนอุณหภูมิ - "ดีกว่าที่จะทำให้มันเรียบง่ายใช่มั้ย"
Leonel Sarmiento

ประเด็นของฉันคือที่ yon ไม่สามารถรับประกันผลลัพธ์ที่คาดหวังได้เพราะหาก temp == แทนที่วิธีของคุณจะไม่ทำงาน
Pier-Alexandre Bouchard

1

นี่คือรุ่นของฉันซึ่งใช้คำ:

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

    }

}

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ที่มีโอกาสในการรับสตริงเปลี่ยนได้ไม่มีอีกครั้ง


1

คำตอบที่สั้นกว่าก็คือ ...

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

1

เมื่อใช้คำตอบที่พบที่นี่คุณสามารถค้นหาสตริงทั้งหมดที่คุณต้องการแทนที่ด้วย

ตัวอย่างเช่นคุณรันโค้ดในคำตอบ SO ด้านบน สร้างดัชนีสองตาราง (สมมติว่า bar และ foo ไม่ปรากฏเพียงครั้งเดียวในสตริงของคุณ) และคุณสามารถทำงานกับตารางเหล่านั้นเพื่อแทนที่พวกเขาในสตริงของคุณ

ตอนนี้สำหรับการแทนที่ตำแหน่งดัชนีเฉพาะที่คุณสามารถใช้:

public static String replaceStringAt(String s, int pos, String c) {
   return s.substring(0,pos) + c + s.substring(pos+1);
}

โดยที่posเป็นดัชนีที่สตริงของคุณเริ่มต้น (จากตารางดัชนีที่ฉันยกมาข้างต้น) สมมติว่าคุณสร้างดัชนีสองตารางสำหรับแต่ละรายการ ขอเรียกพวกเขาและindexBarindexFoo

ตอนนี้ในการแทนที่คุณสามารถเรียกใช้สองลูปได้หนึ่งอันสำหรับการแทนที่แต่ละครั้งที่คุณต้องการ

for(int i=0;i<indexBar.Count();i++)
replaceStringAt(originalString,indexBar[i],newString);

indexFooในทำนองเดียวกันห่วงอีก

สิ่งนี้อาจไม่มีประสิทธิภาพเท่าคำตอบอื่น ๆ ที่นี่ แต่เข้าใจได้ง่ายกว่าแผนที่หรือสิ่งอื่น ๆ

นี่จะให้ผลลัพธ์ที่คุณต้องการเสมอและสำหรับเหตุการณ์ที่อาจเกิดขึ้นหลาย ๆ ครั้งของแต่ละสตริง ตราบใดที่คุณเก็บดัชนีของการเกิดแต่ละครั้ง

อีกทั้งคำตอบนี้ไม่จำเป็นต้องมีการเรียกซ้ำหรือการอ้างอิงภายนอกใด ๆ เท่าที่ความสลับซับซ้อนมันมีค่าเป็น O (n กำลังสอง) ในขณะที่ n คือผลรวมของการปรากฏของคำทั้งสอง


-1

ฉันพัฒนารหัสนี้จะแก้ปัญหา:

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).


2
มันจะใช้ได้ก็ต่อเมื่อมีลักษณะที่ปรากฏของแต่ละสายเพียงเส้นเดียวเท่านั้น
Vic

-1
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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.