【问题标题】:Remove all occurrences of char from string从字符串中删除所有出现的 char
【发布时间】:2011-06-02 08:36:43
【问题描述】:

我可以用这个:

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

有没有办法从 Java 中的字符串中删除所有出现的字符 X

我试过了,但不是我想要的:str.replace('X',' '); //replace with space

【问题讨论】:

  • 你试过替换单个字符串吗?

标签: java string character


【解决方案1】:

使用

public String replaceAll(String regex, String replacement)

会起作用。

用法为str.replace("X", "");

执行

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

返回:

lakjsdf xx

【讨论】:

  • Regex 对此可能有点矫枉过正,除非您仅限于支持 Java 1.4 - 因为版本 1.5 有一个 replace 重载,它需要一个简单的 CharSequence
  • @LukeH,这是 String.replace 的反编译源。它使用正则表达式。我同意它的正则表达式感觉很重,但这就是引擎盖下的内容,即使对于上面接受的答案也是如此。 public String replace(CharSequence var1, CharSequence var2) { return Pattern.compile(var1.toString(), 16).matcher(this).replaceAll(Matcher.quoteReplacement(var2.toString())); }
  • 谢天谢地,这不再是真的了。它不再使用正则表达式。
【解决方案2】:

尝试使用overload that takes CharSequence arguments(例如String)而不是char

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

【讨论】:

  • 第一个参数是正则表达式,有时它不会按预期工作,特别是如果这个字符串来自用户输入。
  • @vsb:不正确。该特定重载的两个参数都是CharSequencedocs.oracle.com/javase/7/docs/api/java/lang/…
  • 如果X是char类型怎么办?
  • @Kunal:我猜你需要先toString 它。所以你的代码看起来像str = str.replace(yourChar.toString(), "");
  • 请注意,您可以使用 unicode 转义,例如不删除非字符str = str.replace("\uffff", "");
【解决方案3】:

如果你想用 Java 字符串做点什么,Commons Lang StringUtils 是个不错的选择。

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

【讨论】:

  • 正是我想要的,可能是因为它看起来比replace 更清晰。
【解决方案4】:

您可以使用str = str.replace("X", "");,如前所述,您会没事的。供您参考,'' 不是空(或有效)字符,但 '\0' 是。

所以你可以改用str = str.replace('X', '\0');

【讨论】:

  • 这是不正确的。 '\0' 将产生一个实际的空字符。 str.replace('X', '\0') 等价于 str.replace("X", "\u0000") 这根本不是OP想要的
【解决方案5】:
String test = "09-09-2012";
String arr [] = test.split("-");
String ans = "";

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

这是我从字符串中删除字符的示例。

【讨论】:

  • 这是非常低效的,尤其是与接受的答案相比。
  • 我认为这个答案有效,但正确答案是更短更快
  • 只用replace代替分割。此外,您不应在循环中使用 += 运算符。
【解决方案6】:

你好试试下面的代码

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

【讨论】:

  • 如果我们有另一个字符串而不是 x,你会怎么做?不错的解决方案!
【解决方案7】:

我喜欢在这个场合使用 RegEx:

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

其中 g 表示全局,因此它将遍历您的整个字符串并将所有 X 替换为 ''; 如果你想同时替换 X 和 x,你只需说:

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

(在此处查看我的小提琴:fiddle

【讨论】:

  • 我猜这可能行得通,但正确答案执行得更快更短,最好尽可能避免使用 RegEx,因为众所周知它比其他方法慢
【解决方案8】:
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"; 给出“deletesalllankstoo”
【解决方案9】:

用replaceAll代替replace

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

这应该会给你想要的答案。

【讨论】:

  • replace 最终使用 replaceAll。查看实施。这就是 String#replace 的实现方式:return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
【解决方案10】:

这是一个 lambda 函数,用于删除作为字符串传递的所有字符

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" ); // –&gt; "Text to modify"

此解决方案考虑到生成的字符串(与replace() 不同)在删除字符时永远不会大于起始字符串。因此,它避免了重复分配和复制,同时像replace() 那样将字符附加到StringBuilder
更不用说在 replace() 中毫无意义地生成 PatternMatcher 实例,这些实例永远不需要删除。
replace() 不同,此解决方案可以一次性删除多个字符。

【讨论】:

  • Lambdas/函数式编程现在非常时髦,但是使用它来创建一个比所选答案长 10 倍的解决方案恕我直言,因此投反对票。
  • str.replace("…", "") 实例化private Pattern(…),然后在生成的模式上调用public String replaceAll(String repl)。因此发生了以下函数调用:return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); – 请参阅 Sal_Vader_808 评论。总而言之,c.a.比我的 hip lambda 解决方案长 3 倍。这里很好地解释了为什么我的 hip lambda 解决方案也更快:Why is Java's String::replace() so slow?
  • in own thing:如果它真的与解决方案的大小有关,那么一些其他解决方案是两倍大或需要外部库的解决方案将更适合批评。自 Java 8 以来多年来一直是该语言的一部分的语言扩展并不真正时髦。评分系统的一个普遍问题是,时间因素比解决方案的质量更重要。因此,越来越多的最新、有时甚至更好的解决方案出现在后排。
  • 我指的是 10 倍的代码而不是执行速度。每次调用它时编译正则表达式模式的任何东西都会慢得多。如果高频使用此类正则表达式,您确实需要缓存已编译的匹配器并重用(OP 没有说明它使用的是什么场景 - 可能是从表单提交中清理数据的罕见场景,或者可以在紧张的情况下使用循环每秒被调用 1000 次)。
  • 关于性能问题,我添加了一个新答案,该答案对提供的各种答案进行了快速基准测试。如果 OP 经常执行此操作,那么他们应该避免使用 String.replace() 选项,因为在后台重复重新编译正则表达式模式的成本非常高。
【解决方案11】:

使用性能基准评估主要答案,确认当前选择的答案会在后台进行昂贵的正则表达式操作

迄今为止,提供的答案有 3 种主要样式(忽略 JavaScript 答案;)):

  • 使用 String.replace(charsToDelete, "");它在后台使用正则表达式
  • 使用 Lambda
  • 使用简单的 Java 实现

就代码大小而言,显然 String.replace 是最简洁的。简单的 Java 实现比 Lambda 更小更干净(恕我直言)(不要误会 - 我经常在适当的地方使用 Lambda)

执行速度从快到慢依次为:简单的 Java 实现、Lambda,然后是 String.replace()(调用正则表达式)。

到目前为止,最快的实现是简单的 Java 实现调整,以便将 StringBuilder 缓冲区预分配到最大可能的结果长度,然后简单地将不在“要删除的字符”字符串中的字符附加到缓冲区。这避免了长度大于 16 个字符的字符串(StringBuilder 的默认分配)会发生的任何重新分配,并且避免了从发生的字符串副本中删除字符的“向左滑动”性能损失是 Lambda 实现。

下面的代码运行一个简单的基准测试,运行每个实现 1,000,000 次并记录经过的时间。

每次运行的确切结果都会有所不同,但执行顺序永远不会改变:

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

Lambda 实现(从 Kaplan 的答案中复制)可能会更慢,因为它会将所有字符“左移一位”到被删除字符的右侧。对于需要删除大量字符的较长字符串,这显然会变得更糟。 Lambda 实现本身也可能存在一些开销。

String.replace 实现,使用正则表达式并在每次调用时执行正则表达式“编译”。对此的优化是直接使用正则表达式并缓存已编译的模式以避免每次编译的成本。

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

【讨论】:

  • 如果按预期调用lambda函数,时间如下(没有人将lambda函数包装到成员函数中)。此外,您的 deleteCharsReplace() 实施错误:它替换了一个字符串“XYZ”,而不是fromString.replace("X", "").replace("Y", "").replace("Z", ""); 需要的“X”、“Y”和“Z”。现在我们得到了正确的时间: Start simple Time: 759 |启动 lambda 时间:1092 |启动 deleteCharsLambda() 时间:1420 |开始替换更正时间:4636
  • “没有人将 lambda 函数包装到成员函数中”——除了在基准场景中调用它以使其与调用其他实现的方式保持一致。
  • 我刚刚意识到 OP 要求删除所有出现的 single 字符,但您的回答改变了处理一组字符的范围。我使用的“已接受”答案实现并没有也从未打算迎合多个角色。所以我更新了上述基准以反映这一点和基准时间。顺便说一句,如果您想增加范围以支持多个字符,则多次调用 replace 是昂贵的。最好切换到对 replaceAll("[XYZ]", "") 的单个调用
  • solution中的函数只在调用时初始化一次。将函数定义附加到函数调用的成员函数中,只会扭曲基准。
  • 几乎不可能通过一次调用来正确地对快速持续时间方法进行基准测试,因为每次调用的方差如此之高。因此,基准测试通常涉及对同一方法的多次重复调用,然后评估总时间以与备选方案的总时间进行比较(或在需要时计算平均值)..
【解决方案12】:

在替换时,您需要将需要删除的字符放在方括号内。示例代码如下:

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

【讨论】:

    【解决方案13】:

    …另一个 lambda
    从原始字符串中复制一个新字符串,但省略要删除的字符

    String text = "removing a special character from a string";
    
    int delete = 'e';
    int[] arr = text.codePoints().filter( c -> c != delete ).toArray();
    
    String rslt = new String( arr, 0, arr.length );
    

    给:rmoving a spcial charactr from a string

    【讨论】:

      猜你喜欢
      • 2012-12-06
      • 2014-08-07
      • 1970-01-01
      • 2020-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多