Sự khác biệt giữa String thay thế () và thay thế All ()


221

Sự khác biệt giữa java.lang.String replace()replaceAll()các phương thức, ngoài việc sử dụng regex sau này là gì? Đối với sự thay thế đơn giản như, thay thế .bằng / , có sự khác biệt?

Câu trả lời:


174

Trong đó java.lang.String, replacephương thức sẽ lấy một cặp char hoặc một cặp CharSequence(trong đó String là một lớp con, vì vậy nó sẽ vui vẻ lấy một cặp String). Các replacephương pháp sẽ thay thế tất cả các lần xuất hiện của một char hay CharSequence. Mặt khác, cả hai Stringđối số đến replaceFirstreplaceAlllà biểu thức chính quy (regex). Sử dụng sai chức năng có thể dẫn đến các lỗi tinh vi.


30
Ngoài ra, theo tài liệu java, mỗi cuộc gọi đến str.replaceAll(regex, repl)giống như Pattern.compile(regex).matcher(str).replaceAll(repl). Vì vậy, có một chi phí lớn tùy thuộc vào mức độ sử dụng của nó.
dùng845279

4
@ user845279 Thật thú vị khi bạn nói rằng vì String#replace(target, replacement)điều tương tự, ngoại trừ nó trích dẫn các chuỗi: Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));Có một số lý do tại sao String#replacesẽ nhanh hơn String#replaceAll? Có vẻ như nó String#replacechỉ thực hiện các hoạt động bổ sung.
Ngựa

1
Chỉ tò mò, trong câu trả lời này là so sánh rõ ràng với replaceAll. Câu trả lời là về nhiều hơnreplace
Manuel Jordan

điều này có nghĩa là thay thế All () sẽ tốn kém hơn do kết hợp regex phải không?
tự hỏi

97

Q: Sự khác biệt giữa các java.lang.Stringphương thức replace()replaceAll(), ngoài điều đó là sử dụng regex sau này.

A: Chỉ là regex. Cả hai đều thay thế tất cả :)

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

Tái bút

Ngoài ra còn có một replaceFirst()(có một regex)


1
Thx cho làm rõ rằng nó chỉ là regex. Làm thế nào tôi muốn họ đã đặt tên nó thay thếWithRegex () thay vì thay All ()
HopeKing

Làm rõ: thayTất cả () hoạt động với các biểu thức chính quy, thay thế () hoạt động với CharSequence
Johnny Five

2
@JohnnyFive Điều đó làm cho nó khó hiểu hơn. Biểu thức thông thường không phải là một loại, CharSequencelà. Cả hai replace()replaceAll()"làm việc với CharSequence". Nó replaceAll()coi cái được đưa ra CharSequencenhư một biểu thức chính quy để nó tìm kiếm kết quả khớp chính tả , trong khi replace()coi cái được đưa ra CharSequencenhư một văn bản tìm kiếm đơn giản để nó tìm kiếm sự xuất hiện của nó.
SantiBailors

43

Cả hai replace()replaceAll()thay thế tất cả các lần xuất hiện trong Chuỗi.

Ví dụ

Tôi luôn tìm thấy những ví dụ hữu ích để hiểu sự khác biệt.

replace()

Sử dụng replace()nếu bạn chỉ muốn thay thế một số charbằng một số khác charhoặc một số Stringkhác String(thực tế CharSequence).

ví dụ 1

Thay thế tất cả các lần xuất hiện của nhân vật xbằng o.

String myString = "__x___x___x_x____xx_";

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

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

Ví dụ 2

Thay thế tất cả các lần xuất hiện của chuỗi fishbằng sheep.

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

Sử dụng replaceAll()nếu bạn muốn sử dụng một mẫu biểu thức chính quy .

Ví dụ 3

Thay thế bất kỳ số nào bằng một 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

Ví dụ 4

Xóa tất cả khoảng trắng.

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

Xem thêm

Tài liệu

Biểu thức chính quy


34

Các replace()phương pháp được quá tải để chấp nhận cả một nguyên thủy charvà một CharSequencenhư các đối số.

Bây giờ, liên quan đến hiệu suất, replace()phương thức này nhanh hơn một chút so với replaceAll()lần đầu tiên sau đó biên dịch mẫu biểu thức chính quy và sau đó khớp trước khi cuối cùng thay thế trong khi phương thức trước chỉ đơn giản khớp với đối số được cung cấp và thay thế.

Vì chúng ta biết khớp mẫu regex phức tạp hơn một chút và do đó chậm hơn, nên việc ưu tiên replace()hơn replaceAll()được đề xuất bất cứ khi nào có thể.

Ví dụ, đối với các thay thế đơn giản như bạn đã đề cập, tốt hơn là sử dụng:

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

thay vì:

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

Lưu ý: các đối số phương thức chuyển đổi ở trên phụ thuộc vào hệ thống.


6
Ngay cả thay thế cũng làm tương tự, Từ java String docs :: public String thay thế (mục tiêu CharSequence, thay thế CharSequence) {return Pattern.compile (target.toString (), Pattern.LITITH) .matcher (this) .replaceAll (Matcher.quoteReplocation (thay thế.toString ())); }
Prateek

@Prateek: sau jdk8, String :: thay thế không sử dụng Mẫu nữa: hg.openjdk.java.net/jdk9/jdk9/jdk/file/65464a307408/src/ tựa , tương tự trong jdk11.
Franck

Đồng ý, trong Java 8 thực tế cả hai phương thức gần như giống nhau, vì cả hai đều xuất hiện Pattern.compile(...)nội dung / phần trong các triển khai của chúng, dường như replaceít phức tạp hơn về cách định nghĩa / gửi đối số đầu tiên. Nó không yêu cầu "\". Hơn nữa replacecó sẵn từ Java 1.5replaceAllkể từ đó1.4
Manuel Jordan

3
String replace(char oldChar, char newChar)

Trả về một chuỗi mới do thay thế tất cả các lần xuất hiện của oldChar trong chuỗi này bằng newChar.

String replaceAll(String regex, String replacement

Thay thế từng chuỗi con của chuỗi này khớp với biểu thức chính quy đã cho bằng thay thế đã cho.


3
  1. Cả thay thế () và thay thế () chấp nhận hai đối số và thay thế tất cả các lần xuất hiện của chuỗi con thứ nhất (đối số thứ nhất) trong một chuỗi bằng chuỗi con thứ hai (đối số thứ hai).
  2. thay thế () chấp nhận một cặp char hoặc char resultence và thayTất cả () chấp nhận một cặp regex.
  3. Không đúng khi thay thế () hoạt động nhanh hơn thay thế All () vì cả hai đều sử dụng cùng một mã trong quá trình triển khai.

    Pattern.compile (regex) .matcher (this) .replaceAll (thay thế);

Bây giờ câu hỏi là khi nào nên sử dụng thay thế và khi nào nên sử dụng thay thế All (). Khi bạn muốn thay thế một chuỗi con bằng một chuỗi con khác bất kể vị trí xuất hiện của nó trong chuỗi sử dụng thay thế (). Nhưng nếu bạn có một số ưu tiên hoặc điều kiện cụ thể như chỉ thay thế các chuỗi con ở đầu hoặc cuối chuỗi, hãy sử dụng thay thế All (). Dưới đây là một số ví dụ để chứng minh quan điểm của tôi:

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
Họ không thực hiện chính xác như nhau. replacekhông gọi Pattern.compile(regex).matcher(this).replaceAll(replacement);. Nó gọiPattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
ChiefTwoP Pencil

thayTất cả () chấp nhận một cặp regex Tại sao cả chuỗi tìm kiếm và chuỗi thay thế đều là regex? Những gì sẽ xảy ra được thay thế bằng? Với một regex? Tất nhiên chỉ có đối số đầu tiên là regex (chuỗi tìm kiếm). Cái thứ hai không phải là regex (chuỗi thay thế).
SantiBailors

1

Như được đề cập trong câu trả lời của wickeD, với thay thếTất cả chuỗi thay thế được xử lý khác nhau giữa thay thế và thay thế. Tôi mong đợi [3] và [4] có cùng giá trị, nhưng chúng khác nhau.

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

Đầu ra của nó là:

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

Điều này khác với perl khi sự thay thế không yêu cầu thêm mức thoát:

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

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

in nào \ X 2

Điều này có thể khá phiền toái, vì khi cố gắng sử dụng giá trị được trả về bởi java.sql.DatabaseMetaData.getSearchStringEscape () với thay thế All ().


0

Chủ đề cũ tôi biết nhưng tôi là người mới đối với Java và khám phá một trong những điều kỳ lạ. Tôi đã sử dụng String.replaceAll()nhưng nhận được kết quả không thể đoán trước.

Một cái gì đó như thế này làm rối tung chuỗi:

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

Vì vậy, tôi đã thiết kế chức năng này để khắc phục vấn đề kỳ lạ:

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

Điều này khiến bạn có thể làm:

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

1
String.replaceAll()mong đợi các biểu thức chính quy không phải là đối số theo nghĩa đen, đó là lý do tại sao bạn nhận được kết quả "không thể đoán trước" (đó thực sự là rất nhiều dự đoán). String.replace()hoạt động theo cách bạn muốn.
Nadar

Theo nguyên tắc khi chúng ta nhận được kết quả không mong muốn từ Java, thay vì thiết kế một hàm mới để khắc phục điều đó, tốt hơn là giả định rằng những kết quả đó là đúng và chúng ta đang hiểu sai chức năng Java mà chúng ta đang sử dụng.
SantiBailors

0

Để thêm vào "Câu trả lời hay nhất" đã được chọn (và những câu trả lời tương tự như của Suragch), String.replace()bị hạn chế bằng cách thay thế các ký tự liên tiếp (do đó lấy CharSequence). Tuy nhiên, String.replaceAll()không bị hạn chế bằng cách chỉ thay thế các ký tự liên tiếp. Bạn có thể thay thế các ký tự không tuần tự cũng như biểu thức chính quy của bạn được xây dựng theo cách như vậy.

Ngoài ra (quan trọng nhất và rõ ràng đau đớn), replace()chỉ có thể thay thế các giá trị theo nghĩa đen; trong khi đó replaceAllcó thể thay thế các chuỗi 'like' (không nhất thiết phải giống hệt nhau).


-1

replace()phương thức không sử dụng mẫu regex trong khi replaceAll()phương thức sử dụng mẫu regex. Vì vậy, replace()thực hiện nhanh hơn replaceAll().


3
Đo không phải sự thật. Nếu bạn nhìn vào nguồn thay thế, bạn sẽ thấy nó cũng đã sử dụng Mẫu và
Trình so khớp

-5

thay thế hoạt động trên kiểu dữ liệu char nhưng thay thế All hoạt động trên kiểu dữ liệu chuỗi và cả hai thay thế tất cả các lần xuất hiện của đối số thứ nhất bằng đối số thứ hai.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.