ความแตกต่างระหว่าง String replace () และ replaceAll ()


221

ความแตกต่างระหว่าง java.lang.String replace()กับreplaceAll()วิธีการอื่นที่ไม่ใช่ภายหลังใช้ regex คืออะไร สำหรับการทดแทนอย่างง่ายเช่นแทนที่.ด้วย/ จะมีความแตกต่างหรือไม่?

คำตอบ:


174

ในjava.lang.Stringการreplaceใช้วิธีการอย่างใดอย่างหนึ่งจะใช้เวลาคู่ของถ่านหรือคู่ของหนึ่งCharSequence's (ซึ่ง String เป็น subclass ดังนั้นจึงจะใช้เวลาอย่างมีความสุขคู่ของสตริงของ) วิธีการจะเข้ามาแทนที่เกิดขึ้นทั้งหมดของถ่านหรือreplace CharSequenceในทางกลับกันStringอาร์กิวเมนต์ทั้งสองreplaceFirstและreplaceAllนิพจน์ทั่วไป (regex) การใช้ฟังก์ชั่นที่ไม่ถูกต้องสามารถนำไปสู่ข้อบกพร่องที่ลึกซึ้ง


30
นอกจากนี้ตามเอกสาร Java, การโทรแต่ละครั้งจะเป็นเช่นเดียวกับstr.replaceAll(regex, repl) Pattern.compile(regex).matcher(str).replaceAll(repl)ดังนั้นจึงมีค่าใช้จ่ายขนาดใหญ่ขึ้นอยู่กับปริมาณการใช้งาน
user845279

4
@ user845279 เป็นที่น่าสนใจที่คุณจะบอกว่าตั้งแต่String#replace(target, replacement)ทำสิ่งเดียวกันยกเว้นมันเป็นคำพูดสตริง: Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));มีเหตุผลทำไมString#replaceจะเร็วกว่าบางString#replaceAll? ดูเหมือนจะไม่เป็นเช่นนั้นเนื่องจากString#replaceเพิ่งดำเนินการเพิ่มเติม
Horsey

1
แค่อยากรู้อยากเห็นในคำตอบนี้เปรียบเทียบที่ชัดเจนกับreplaceAllที่ไหน คำตอบนั้นเกี่ยวกับreplace
มานูเอลจอร์แดน

ซึ่งหมายความว่า replaceAll () จะเป็นค่าใช้จ่ายเนื่องจากการจับคู่ regex ใช่ไหม
สงสัย

98

ถาม:อะไรคือความแตกต่างระหว่างjava.lang.Stringวิธีการreplace()และreplaceAll()นอกเหนือจากที่ใช้ในภายหลัง regex

A:แค่ regex พวกเขาทั้งสองแทนที่ทั้งหมด :)

http://docs.oracle.com/javase/6/docs/api/java/lang/String.html

PS:

นอกจากนี้ยังมีreplaceFirst()(ซึ่งต้องใช้ regex)


1
ขอบคุณสำหรับการชี้แจงว่ามันเป็นเพียง regex ฉันหวังว่าพวกเขาจะตั้งชื่อว่า replaceWithRegex () แทน replaceAll ()
HopeKing

ชี้แจง: replaceAll () ทำงานร่วมกับนิพจน์ทั่วไปแทนที่ () ทำงานร่วมกับ CharSequence
Johnny Five

2
@JohnnyFive ที่ทำให้สับสนมากขึ้น นิพจน์ทั่วไปไม่ใช่ชนิดCharSequenceคือ ทั้งreplace()และreplaceAll()"ทำงานกับCharSequence" มันเป็นเรื่องที่replaceAll()จะพิจารณาให้CharSequenceเป็นนิพจน์ปกติดังนั้นจึงมองหาไม้ขีดไฟ regexในขณะที่replace()พิจารณาให้CharSequenceเป็นค้นหาข้อความธรรมดาดังนั้นจึงมองหาการเกิดขึ้นของมัน
SantiBailors

44

ทั้งสองreplace()และreplaceAll()แทนที่เกิดขึ้นทั้งหมดในสตริง

ตัวอย่าง

ฉันมักจะพบตัวอย่างที่เป็นประโยชน์ในการทำความเข้าใจความแตกต่าง

replace()

ใช้replace()หากคุณต้องการแทนที่บางส่วนcharด้วยอันอื่นcharหรืออันใดStringอันหนึ่งString(อันที่จริงCharSequence)

ตัวอย่างที่ 1

แทนที่เกิดขึ้นทั้งหมดของตัวละครด้วยxo

String myString = "__x___x___x_x____xx_";

char oldChar = 'x';
char newChar = 'o';

String newString = myString.replace(oldChar, newChar);
// __o___o___o_o____oo_

ตัวอย่างที่ 2

แทนที่เกิดขึ้นทั้งหมดของสตริงกับfishsheep

String myString = "one fish, two fish, three fish";

String target = "fish";
String replacement = "sheep";

String newString = myString.replace(target, replacement);
// one sheep, two sheep, three sheep

replaceAll()

ใช้replaceAll()ถ้าคุณต้องการที่จะใช้รูปแบบการแสดงออกปกติ

ตัวอย่างที่ 3

เปลี่ยนหมายเลขใด ๆ xกับ

String myString = "__1_6____3__6_345____0";

String regex = "\\d";
String replacement = "x";

String newString = myString.replaceAll(regex, replacement); 
// __x_x____x__x_xxx____x

ตัวอย่างที่ 4

ลบช่องว่างทั้งหมด

String myString = "   Horse         Cow\n\n   \r Camel \t\t Sheep \n Goat        ";

String regex = "\\s";
String replacement = "";

String newString = myString.replaceAll(regex, replacement); 
// HorseCowCamelSheepGoat

ดูสิ่งนี้ด้วย

เอกสาร

นิพจน์ทั่วไป


34

replace()วิธีการมากเกินไปที่จะยอมรับทั้งดั้งเดิมcharและCharSequenceเป็นข้อโต้แย้ง

ตอนนี้เท่าที่ประสิทธิภาพเป็นห่วงreplace()วิธีการนั้นเร็วกว่าreplaceAll()เพราะก่อนรวบรวมรูปแบบ regex แล้วจับคู่ก่อนแทนที่ในที่สุดในขณะที่อดีตเพียงแค่ตรงกับอาร์กิวเมนต์ที่ให้ไว้และแทนที่

เนื่องจากเราทราบว่าการจับคู่รูปแบบ regex มีความซับซ้อนมากขึ้นและช้าลงจึงแนะนำให้เลือกreplace()มากกว่าreplaceAll()ทุกครั้งที่ทำได้

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

replace('.', '\\');

แทน:

replaceAll("\\.", "\\\\");

หมายเหตุ: อาร์กิวเมนต์วิธีการแปลงข้างต้นขึ้นอยู่กับระบบ


6
แม้แทนที่ยังทำเช่นเดียวกันจาก java String docs :: public String replace (เป้าหมาย CharSequence, การแทนที่ CharSequence) {return Pattern.compile (target.toString (), Pattern.LITERAL) .matcher (นี่) .replaceAll (Matcher.quoteReplacement (replacement.toString ())); }
Prateek

@Prateek: หลังจาก jdk8, String :: replace ไม่ได้ใช้รูปแบบอีกต่อไป: hg.openjdk.java.net/jdk9/jdk9/jdk/file/65464a307408/src/ …เหมือนกันใน jdk11
Franck

เห็นด้วยใน Java 8 ในทางปฏิบัติทั้งสองวิธีเกือบจะเหมือนกันสำหรับทั้งสองปรากฏPattern.compile(...)เนื้อหา / ส่วนในการใช้งานของพวกเขาดูเหมือนว่าreplaceซับซ้อนน้อยกว่าเกี่ยวกับวิธีการกำหนด / ส่งอาร์กิวเมนต์แรก "\"มันไม่จำเป็นต้อง นอกจากนี้ยังreplaceมีให้ตั้งแต่ Java 1.5และreplaceAllตั้งแต่1.4
Manuel Jordan

3
String replace(char oldChar, char newChar)

ส่งคืนสตริงใหม่ที่เป็นผลมาจากการแทนที่ oldChar ทั้งหมดที่เกิดขึ้นในสตริงนี้ด้วย newChar

String replaceAll(String regex, String replacement

แทนที่แต่ละสตริงย่อยของสตริงนี้ที่ตรงกับนิพจน์ทั่วไปที่กำหนดด้วยการแทนที่ที่กำหนด


3
  1. ทั้ง replace () และ replaceAll () ยอมรับสองอาร์กิวเมนต์และแทนที่สตริงย่อยแรก (อาร์กิวเมนต์แรก) ทั้งหมดในสตริงที่มีสตริงย่อยที่สอง (อาร์กิวเมนต์ที่สอง)
  2. แทนที่ () ยอมรับคู่ของถ่านหรือผลสืบเนื่องและ replaceAll () ยอมรับคู่ของ regex
  3. ไม่เป็นความจริงที่ replace () จะทำงานได้เร็วกว่า replaceAll () เนื่องจากทั้งคู่ใช้รหัสเดียวกันในการนำไปใช้

    Pattern.compile (regex) .matcher (นี้) .replaceAll (ทดแทน);

ตอนนี้คำถามคือเมื่อจะใช้แทนที่และเมื่อใดที่จะใช้ replaceAll () เมื่อคุณต้องการแทนที่สตริงย่อยด้วยสตริงย่อยอื่นโดยไม่คำนึงถึงตำแหน่งที่เกิดขึ้นในสตริงให้ใช้ replace () แต่ถ้าคุณมีการตั้งค่าหรือเงื่อนไขบางอย่างเช่นแทนที่เฉพาะสตริงย่อยที่จุดเริ่มต้นหรือจุดสิ้นสุดของสตริงให้ใช้ replaceAll () นี่คือตัวอย่างที่จะพิสูจน์จุดของฉัน:

String str = new String("==qwerty==").replaceAll("^==", "?"); \\str: "?qwerty=="
String str = new String("==qwerty==").replaceAll("==$", "?"); \\str: "==qwerty?"
String str = new String("===qwerty==").replaceAll("(=)+", "?"); \\str: "?qwerty?"

4
พวกเขาไม่ได้ใช้งานเดียวกันแน่นอน ไม่เรียกreplace Pattern.compile(regex).matcher(this).replaceAll(replacement);มันเรียกPattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
ChiefTwoPencils

replaceAll () ยอมรับคู่ของ regexทำไมทั้งสตริงการค้นหาและสตริงการแทนที่จึงเป็น regex สิ่งที่จะเกิดขึ้นจะถูกแทนที่ด้วย? ด้วย regex หรือไม่? แน่นอนว่าอาร์กิวเมนต์แรกเท่านั้นคือ regex (สตริงการค้นหา) อันที่สองไม่ใช่ regex (สายอักขระการแทนที่)
SantiBailors

1

ตามที่กล่าวถึงในคำตอบของ wickeD ด้วย replaceAll สตริงการแทนที่จะถูกจัดการแตกต่างกันระหว่าง replace และ replaceAll ฉันคาดว่า [3] และ [4] จะมีค่าเท่ากัน

public static void main(String[] args) {
    String[] a = new String[5];
    a[0] = "\\";
    a[1] = "X";
    a[2] = a[0] + a[1];
    a[3] = a[1].replaceAll("X", a[0] + "X");
    a[4] = a[1].replace("X", a[0] + "X");

    for (String s : a) {
        System.out.println(s + "\t" + s.length());
    }
}

ผลลัพธ์ของสิ่งนี้คือ:

\   1
X   1
\X  2
X   1
\X  2

ซึ่งแตกต่างจาก perl ที่การเปลี่ยนไม่จำเป็นต้องมีระดับพิเศษในการหลบหนี:

#!/bin/perl
$esc = "\\";
$s = "X";

$s =~ s/X/${esc}X/;
print "$s " . length($s) . "\n";

ซึ่งพิมพ์ \ X 2

สิ่งนี้อาจสร้างความรำคาญเช่นเดียวกับเมื่อพยายามใช้ค่าที่ส่งคืนโดย java.sql.DatabaseMetaData.getSearchStringEscape () ด้วย replaceAll ()


0

หัวข้อเก่าที่ฉันรู้ แต่ฉันเป็นคนใหม่ของ Java และค้นพบหนึ่งในสิ่งที่แปลก ฉันเคยใช้String.replaceAll()แต่ได้ผลลัพธ์ที่คาดเดาไม่ได้

บางสิ่งบางอย่างเช่นนี้ทำให้สาย:

sUrl = sUrl.replaceAll( "./", "//").replaceAll( "//", "/");

ดังนั้นฉันจึงออกแบบฟังก์ชันนี้เพื่อแก้ไขปัญหาแปลก ๆ :

//String.replaceAll does not work OK, that's why this function is here
public String strReplace( String s1, String s2, String s ) 
{
    if((( s == null ) || (s.length() == 0 )) || (( s1 == null ) || (s1.length() == 0 )))
     { return s; }

   while( (s != null) && (s.indexOf( s1 ) >= 0) )
    { s = s.replace( s1, s2 ); }
  return s;
}

ซึ่งทำให้คุณสามารถทำ:

sUrl=this.strReplace("./", "//", sUrl );
sUrl=this.strReplace( "//", "/", sUrl );

1
String.replaceAll()คาดหวังว่านิพจน์ทั่วไปไม่ใช่ข้อโต้แย้งที่แท้จริงซึ่งเป็นสาเหตุที่คุณได้รับผลลัพธ์ที่ "คาดเดาไม่ได้" (ซึ่งเป็นผลลัพธ์ที่คาดการณ์ได้จริง ๆ ) String.replace()ทำงานในแบบที่คุณต้องการ
นาดาร์

ตามกฎง่ายๆเมื่อเราได้รับผลลัพธ์ที่ไม่คาดคิดจาก Java แทนที่จะออกแบบฟังก์ชั่นใหม่เพื่อหลีกเลี่ยงปัญหานั้นดีกว่าที่จะสมมติว่าผลลัพธ์เหล่านั้นผิดพลาดและเราเข้าใจผิดเกี่ยวกับฟังก์ชัน Java ที่เรากำลังใช้
SantiBailors

0

เพื่อเพิ่มเลือก "คำตอบที่ดีที่สุด" (และคนอื่น ๆ ที่เป็นเพียงที่ดีเช่น Suragch ของ) String.replace()เป็นข้อ จำกัด โดยการแทนที่ตัวอักษรที่มีลำดับ (ซึ่งเป็นการดำเนินการCharSequence) อย่างไรก็ตามString.replaceAll()จะไม่ถูก จำกัด โดยการแทนที่อักขระตามลำดับเท่านั้น คุณสามารถแทนที่อักขระที่ไม่ต่อเนื่องได้ตราบใดที่นิพจน์ทั่วไปของคุณถูกสร้างขึ้นในลักษณะดังกล่าว

นอกจากนี้ (ที่สำคัญที่สุดและชัดเจนอย่างเจ็บปวด) replace()สามารถแทนที่ค่าตามตัวอักษรเท่านั้น ในขณะที่replaceAllสามารถแทนที่ลำดับ 'ชอบ' (ไม่จำเป็นต้องเหมือนกัน)


-1

replace()method ไม่ใช้รูปแบบ regex ในขณะที่replaceAll()method ใช้รูปแบบ regex ดังนั้นการดำเนินการได้เร็วกว่าreplace()replaceAll()


3
ที่ไม่เป็นความจริง. หากคุณดูที่แหล่งที่มาของการแทนที่คุณจะเห็นว่ามันใช้รูปแบบและตัวจับคู่ (เช่น regex)
xtrakBandit

-5

แทนที่ทำงานบนชนิดข้อมูลถ่าน แต่ replaceAll ทำงานบนสตริงประเภทข้อมูลและทั้งคู่จะแทนที่อาร์กิวเมนต์แรกทั้งหมดด้วยอาร์กิวเมนต์ที่สอง

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