Xóa tất cả các lần xuất hiện của char khỏi chuỗi


311

Tôi có thể sử dụng cái này:

String str = "TextX Xto modifyX";
str = str.replace('X','');//that does not work because there is no such character ''

Có cách nào để loại bỏ tất cả các lần xuất hiện của ký tự Xkhỏi Chuỗi trong Java không?

Tôi đã thử điều này và không phải là những gì tôi muốn: str.replace('X',' '); //replace with space


3
Bạn đã thử thay thế các chuỗi ký tự đơn chưa?
peter.m bồ.rust

Câu trả lời:


523

Hãy thử sử dụng quá tải có các CharSequenceđối số (ví dụ String:) thay vì char:

str = str.replace("X", "");

2
Đối số đầu tiên là biểu thức chính quy, đôi khi nó sẽ không hoạt động như mong đợi, đặc biệt nếu chuỗi này đến từ đầu vào của người dùng.
vbezhenar

9
@vsb: Không đúng. Cả hai đối số của sự quá tải cụ thể là CharSequence. docs.oracle.com/javase/7/docs/api/java/lang/...
LukeH

Phải làm gì trong trường hợp Xloại char?
KNU

7
@Kunal: Tôi đoán bạn cần toStringnó trước. Vì vậy, mã của bạn sẽ trông giống nhưstr = str.replace(yourChar.toString(), "");
LukeH

Lưu ý rằng bạn có thể sử dụng các lối thoát unicode, ví dụ: không xóa các ký tự khôngstr = str.replace("\uffff", "");
Jaime Hablutzel

42

Sử dụng

public String replaceAll(String regex, String replacement)

sẽ làm việc.

Cách sử dụng sẽ là str.replace("X", "");.

Thi công

"Xlakjsdf Xxx".replaceAll("X", "");

trả về:

lakjsdf xx

6
Regex có lẽ quá mức cần thiết cho điều này trừ khi bạn bị hạn chế hỗ trợ Java 1.4 - vì phiên bản 1.5 có replacequá tải đơn giản CharSequence.
LukeH

3
@LukeH, Đây là nguồn được dịch ngược sang String.replace. Đó là sử dụng regex. Tôi đồng ý rằng regex cảm thấy nặng nề, nhưng đó là những gì nằm dưới mui xe ngay cả đối với câu trả lời được chấp nhận ở trên. chuỗi thay thế công khai (CharSequence var1, CharSequence var2) {return Pattern.compile (var1.toString (), 16) .matcher (this) .replaceAll (Matcher.quoteReplocation (var2.toString ())); }
Perry Tew

24

Nếu bạn muốn làm một cái gì đó với Chuỗi Java, Commons Lang StringUtils là một nơi tuyệt vời để tìm kiếm.

StringUtils.remove("TextX Xto modifyX", 'X');

chính xác những gì tôi tìm kiếm, có lẽ bởi vì nó trông rõ ràng hơn replace.
Dòng

6
String test = "09-09-2012";
String arr [] = test.split("-");
String ans = "";

for(String t : arr)
    ans+=t;

Đây là ví dụ cho nơi tôi đã xóa ký tự - khỏi Chuỗi.


4
Điều này rất không hiệu quả, đặc biệt là so với câu trả lời được chấp nhận.
Erick Robertson

3
Tôi nghĩ rằng câu trả lời này hoạt động, nhưng câu trả lời chính xác thì nó ngắn hơn và nhanh hơn
evilReiko

2

Tôi thích sử dụng RegEx trong dịp này:

str = str.replace(/X/g, '');

Trong đó g có nghĩa là toàn cầu nên nó sẽ đi qua toàn bộ chuỗi của bạn và thay thế tất cả X bằng ''; nếu bạn muốn thay thế cả X và x, bạn chỉ cần nói:

str = str.replace(/X|x/g, '');

(xem fiddle của tôi ở đây: fiddle )


Tôi đoán điều này có thể hoạt động, nhưng câu trả lời đúng thực thi nhanh hơn và ngắn hơn, tốt hơn hết là tránh RegEx càng nhiều càng tốt vì nó được biết là chậm hơn các phương pháp khác
evilReiko

2

Xin chào Hãy thử mã này dưới đây

public class RemoveCharacter {

    public static void main(String[] args){
        String str = "MXy nameX iXs farXazX";
        char x = 'X';
        System.out.println(removeChr(str,x));
    }

    public static String removeChr(String str, char x){
        StringBuilder strBuilder = new StringBuilder();
        char[] rmString = str.toCharArray();
        for(int i=0; i<rmString.length; i++){
            if(rmString[i] == x){

            } else {
                strBuilder.append(rmString[i]);
            }
        }
        return strBuilder.toString();
    }
}

Làm thế nào bạn sẽ làm điều này nếu thay vì x chúng tôi có một chuỗi khác? Giải pháp tốt đẹp!
Mona Jalal

2

Sử dụng thay thế Tất cả thay vì thay thế

str = str.replaceAll("X,"");

Điều này sẽ cung cấp cho bạn câu trả lời mong muốn.


thay thế kết thúc bằng cách sử dụng thay thế. Nhìn vào thực hiện. Đây là cách thực hiện Chuỗi # thay thế:return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
Sal_Vader_808

0
package com.acn.demo.action;

public class RemoveCharFromString {

    static String input = "";
    public static void main(String[] args) {
        input = "abadbbeb34erterb";
        char token = 'b';
        removeChar(token);
    }

    private static void removeChar(char token) {
        // TODO Auto-generated method stub
        System.out.println(input);
        for (int i=0;i<input.length();i++) {
            if (input.charAt(i) == token) {
            input = input.replace(input.charAt(i), ' ');
                System.out.println("MATCH FOUND");
            }
            input = input.replaceAll(" ", "");
            System.out.println(input);
        }
    }
}

input = "deletes all blanks too";đưa ra "deletesalllankstoo"
Kaplan

0

đây là hàm lambda loại bỏ tất cả các ký tự được truyền dưới dạng chuỗi

BiFunction<String,String,String> deleteChars = (fromString, chars) -> {
  StringBuilder buf = new StringBuilder( fromString );
  IntStream.range( 0, buf.length() ).forEach( i -> {
    while( i < buf.length() && chars.indexOf( buf.charAt( i ) ) >= 0 )
      buf.deleteCharAt( i );
  } );
  return( buf.toString() );
};

String str = "TextX XYto modifyZ";
deleteChars.apply( str, "XYZ" ); // –> "Text to modify"

Giải pháp này đưa ra kết luận rằng Chuỗi kết quả - khác với replace()- không bao giờ trở nên lớn hơn Chuỗi bắt đầu khi xóa các ký tự. Vì vậy, nó tránh được sự lặp đi lặp lại việc phân bổ và sao chép trong khi phụ thêm nhân vật khôn ngoan đến StringBuildernhư replace()vậy.
Không đề cập đến thế hệ vô nghĩa Patternvà các Matchertrường hợp trong replace()đó không bao giờ cần thiết để loại bỏ.
Khác với replace()giải pháp này có thể xóa một vài ký tự trong một swoop.


Ngay lập tức Lambdas / Lập trình chức năng rất hiện đại nhưng việc sử dụng nó để tạo ra một giải pháp dài hơn 10 lần so với câu trả lời được chọn không thể được chứng minh IMHO, do đó bỏ phiếu.
Volksman

str.replace("…", "")khởi tạo private Pattern(…)và sau đó trên các cuộc gọi mẫu được tạo public String replaceAll(String repl). Vì vậy, các cuộc gọi chức năng sau đây đã xảy ra: return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); - xem bình luận Sal_Vader_808. Tất cả trong tất cả ca dài hơn 3 lần so với giải pháp lambda hông của tôi . Và ở đây, nó được giải thích độc đáo tại sao giải pháp lambda hông của tôi cũng nhanh hơn: Tại sao String :: Java (thay thế) lại chậm như vậy?
Kaplan

theo cách riêng : Nếu nó thực sự có kích thước của giải pháp, một số giải pháp khác lớn gấp đôi hoặc các giải pháp yêu cầu thư viện bên ngoài sẽ là ứng cử viên phù hợp hơn cho phê bình. Một phần mở rộng ngôn ngữ đã là một phần của ngôn ngữ trong nhiều năm kể từ khi Java 8 không thực sự phù hợp . Một vấn đề chung với hệ thống tính điểm là, yếu tố thời gian nặng hơn chất lượng của một giải pháp. Do đó, các giải pháp cập nhật hơn và đôi khi thậm chí tốt hơn đang ngày càng được tìm thấy ở phần ba.
Kaplan

Tôi đã đề cập đến 10 lần dài hơn về mặt mã không phải tốc độ thực thi. Bất cứ điều gì biên dịch một mẫu biểu thức chính quy mỗi lần nó được gọi có thể chậm hơn nhiều. Bạn thực sự cần phải lưu bộ đệm của trình so khớp đã biên dịch và sử dụng lại nếu sử dụng regex như vậy ở tần số cao (OP không cho biết kịch bản nào được sử dụng - có thể là một kịch bản hiếm gặp để làm sạch dữ liệu từ việc gửi biểu mẫu hoặc có thể được sử dụng chặt chẽ vòng lặp được gọi là 1000 lần một giây).
Volksman

Liên quan đến các mối quan tâm về hiệu suất, tôi đã thêm một câu trả lời mới chạy điểm chuẩn nhanh trên nhiều câu trả lời được cung cấp. Nếu OP thực hiện thao tác này thường xuyên thì họ nên tránh tùy chọn String.replace () vì việc biên dịch lại mẫu regex dưới mui xe rất tốn kém.
Volksman

0

Đánh giá các câu trả lời chính với điểm chuẩn hiệu suất xác nhận mối lo ngại rằng câu trả lời được chọn hiện tại làm cho các hoạt động regex tốn kém dưới mui xe

Đến nay, các câu trả lời được cung cấp có 3 kiểu chính (bỏ qua câu trả lời JavaScript;)):

  • Sử dụng String.replace (charsToDelete, ""); trong đó sử dụng regex dưới mui xe
  • Sử dụng Lambda
  • Sử dụng triển khai Java đơn giản

Về kích thước mã rõ ràng, String.replace là ngắn gọn nhất. Việc triển khai Java đơn giản nhỏ hơn và gọn gàng hơn (IMHO) so với Lambda (đừng hiểu sai ý tôi - Tôi thường sử dụng Lambdas khi chúng phù hợp)

Tốc độ thực thi là, theo thứ tự nhanh nhất đến chậm nhất: triển khai Java đơn giản, Lambda và sau đó là String.replace () (gọi ra regex).

Cho đến nay, việc triển khai nhanh nhất là việc triển khai Java đơn giản được điều chỉnh sao cho nó mở rộng bộ đệm StringBuilder với độ dài kết quả tối đa có thể và sau đó chỉ cần thêm các ký tự vào bộ đệm không nằm trong chuỗi "ký tự để xóa". Điều này tránh mọi phân bổ sẽ xảy ra đối với các chuỗi có độ dài> 16 ký tự (phân bổ mặc định cho StringBuilder) và nó tránh được hiệu năng "trượt sang trái" của việc xóa các ký tự khỏi bản sao của chuỗi xảy ra là triển khai Lambda.

Mã dưới đây chạy thử nghiệm điểm chuẩn đơn giản, chạy mỗi lần thực hiện 1.000.000 lần và ghi lại thời gian đã trôi qua.

Kết quả chính xác thay đổi theo từng lần chạy nhưng thứ tự hiệu suất không bao giờ thay đổi:

Start simple Java implementation
Time: 157 ms
Start Lambda implementation
Time: 253 ms
Start String.replace implementation
Time: 634 ms

Việc triển khai Lambda (như được sao chép từ câu trả lời của Kaplan) có thể chậm hơn vì nó thực hiện "dịch chuyển sang trái bởi một" của tất cả các ký tự ở bên phải của ký tự bị xóa. Điều này rõ ràng sẽ trở nên tồi tệ hơn đối với các chuỗi dài hơn với nhiều ký tự yêu cầu xóa. Ngoài ra, có thể có một số chi phí trong việc thực hiện Lambda.

Việc triển khai String.replace, sử dụng regex và thực hiện "biên dịch" regex tại mỗi cuộc gọi. Tối ưu hóa điều này sẽ là sử dụng regex trực tiếp và lưu trữ mẫu đã biên dịch để tránh chi phí biên dịch nó mỗi lần.

package com.sample;

import java.util.function.BiFunction;
import java.util.stream.IntStream;

public class Main {

    static public String deleteCharsSimple(String fromString, String charsToDelete)
    {
        StringBuilder buf = new StringBuilder(fromString.length()); // Preallocate to max possible result length
        for(int i = 0; i < fromString.length(); i++)
            if (charsToDelete.indexOf(fromString.charAt(i)) < 0)
                buf.append(fromString.charAt(i));   // char not in chars to delete so add it
        return buf.toString();
    }

    static public String deleteCharsLambda(String fromString1, String charsToDelete)
    {
        BiFunction<String, String, String> deleteChars = (fromString, chars) -> {
            StringBuilder buf = new StringBuilder(fromString);
            IntStream.range(0, buf.length()).forEach(i -> {
                while (i < buf.length() && chars.indexOf(buf.charAt(i)) >= 0)
                    buf.deleteCharAt(i);
            });
            return (buf.toString());
        };

        return deleteChars.apply(fromString1, charsToDelete);
    }

    static public String deleteCharsReplace(String fromString, String charsToDelete)
    {
        return fromString.replace(charsToDelete, "");
    }


    public static void main(String[] args)
    {
        String str = "XXXTextX XXto modifyX";
        String charsToDelete = "X";  // Should only be one char as per OP's requirement

        long start, end;

        System.out.println("Start simple");
        start = System.currentTimeMillis();

        for (int i = 0; i < 1000000; i++)
            deleteCharsSimple(str, charsToDelete);

        end = System.currentTimeMillis();
        System.out.println("Time: " + (end - start));

        System.out.println("Start lambda");
        start = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++)
            deleteCharsLambda(str, charsToDelete);

        end = System.currentTimeMillis();
        System.out.println("Time: " + (end - start));

        System.out.println("Start replace");
        start = System.currentTimeMillis();

        for (int i = 0; i < 1000000; i++)
            deleteCharsReplace(str, charsToDelete);

        end = System.currentTimeMillis();
        System.out.println("Time: " + (end - start));
    }
}

Nếu hàm lambda được gọi như dự định thực hiện, thì thời gian là như sau (không ai bọc hàm lambda thành hàm thành viên) . Hơn nữa, việc xóaCharsReplace () của bạn được triển khai sai: nó thay thế một Chuỗi "XYZ" và không theo yêu cầu 'X', 'Y' và 'Z' những gì fromString.replace("X", "").replace("Y", "").replace("Z", "");cần thiết. Bây giờ chúng ta có được thời gian chính xác: Bắt đầu đơn giản Thời gian: 759 | Bắt đầu lambda Thời gian: 1092 | Bắt đầu xóaCharsLambda () Thời gian: 1420 | Bắt đầu thay thế Thời gian đã sửa: 4636
Kaplan

"không ai kết hợp chức năng lambda thành chức năng thành viên" - ngoại trừ mục đích gọi nó trong kịch bản điểm chuẩn sao cho phù hợp với cách gọi của các triển khai khác.
Volksman

Tôi chỉ nhận ra rằng OP được hỏi về loại bỏ tất cả các lần xuất hiện của một đơn nhân vật nhưng câu trả lời của bạn thay đổi phạm vi để đối phó với một tập hợp các ký tự. Việc thực hiện câu trả lời "được chấp nhận" mà tôi đã sử dụng không và không bao giờ có ý định phục vụ cho nhiều nhân vật. Vì vậy, tôi đã cập nhật điểm chuẩn trên để phản ánh điều này và thời gian chuẩn. BTW nếu bạn muốn tăng phạm vi để hỗ trợ nhiều ký tự gọi thay thế nhiều lần thì tốn kém. Tốt hơn là chuyển sang một cuộc gọi duy nhất để thay thế All ("[XYZ]", "")
Volksman

Hàm như trong giải pháp chỉ được kích hoạt một lần khi được gọi. Để bọc hàm definiton thêm vào lệnh gọi hàm vào hàm thành viên chỉ có tác dụng làm biến dạng điểm chuẩn.
Kaplan

Hầu như không thể đánh giá đúng các phương thức thời lượng nhanh bằng cách thực hiện một cuộc gọi vì phương sai của mỗi cuộc gọi rất cao. Vì vậy, điểm chuẩn thường bao gồm nhiều cuộc gọi lặp lại cho cùng một phương thức và sau đó tổng thời gian được ước tính để so sánh với tổng số lần thay thế (hoặc để tính trung bình nếu được yêu cầu) ..
Volksman

0

Bạn sẽ cần phải đặt các ký tự cần được loại bỏ bên trong dấu ngoặc vuông trong thời gian thay thế. Mã ví dụ sẽ như sau:

String s = "$116.42".replaceAll("[$]", "");

-3

Bạn có thể sử dụng str = str.replace("X", "");như đã đề cập trước đó và bạn sẽ ổn thôi. Đối với thông tin của bạn ''không phải là một ký tự trống (hoặc hợp lệ) mà '\0'là.

Vì vậy, bạn có thể sử dụng str = str.replace('X', '\0');thay thế.


9
điều này là không đúng. '\ 0' sẽ tạo ra một ký tự null thực tế. str.replace ('X', '\ 0') tương đương với str.replace ("X", "\ u0000") không hoàn toàn là những gì OP muốn
Andrey
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.