代码之家  ›  专栏  ›  技术社区  ›  polyglot

如何在Java中仅用一次ReXEX替换字符串?

  •  22
  • polyglot  · 技术社区  · 15 年前

    我需要用更大的字符串替换动态子字符串,但只需要一次(即第一次匹配)。字符串类只提供 replace() ,替换子字符串的所有实例;有一个 replaceFirst() 方法,但它只接受regexp而不是正则字符串。我有两个关于使用regex的问题:

    1)我的子字符串是动态的,所以可能包含一些奇怪的字符,这在regex中意味着其他东西,我不想处理字符转义。

    2)这种替换经常发生,我不确定使用regex是否会影响性能。我不能预先编译regex,因为regex本身是动态的!

    我一定是错过了什么,因为在我看来这是一件非常基本的事情…在Java FrangeWork中是否有一个替换字符串的方法?

    7 回复  |  直到 6 年前
        1
  •  13
  •   Alex Martelli    15 年前

    使用 bigString.indexof(smallString) 获取大字符串中第一个出现的小字符串的索引(如果没有,则为-1,在这种情况下完成)。然后,使用 bigString.substring 在赛前和赛后拿到大绳子的碎片,最后 concat 把之前和之后的部分放回一起,把你想要的替代品放在中间。

        2
  •  24
  •   Daniel Gerber    6 年前

    您应该使用已经测试过并且有良好文档记录的库来编写自己的代码!

    StringUtils.replaceOnce("aba", "a", "")    = "ba"
    

    这个 StringUtils 类来自 Apache Commons Lang3 包,可以这样导入Maven:

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.8.1</version>
    </dependency>
    
        3
  •  15
  •   Bennett McElwee    15 年前

    正如劳伦斯建议的,你可以使用 Pattern.quote 这样地:

    newString = string.replaceFirst(Pattern.quote(substring), replacement);
    

    这将创建一个与子字符串完全匹配的新regex。另一种方法是简单地将子字符串编译为文本regex,如下所示:

    newString = Pattern.compile(substring, Pattern.LITERAL).
            matcher(string).replaceFirst(replacement);
    

    这可能稍微更有效率,但也不太清楚。

    您也可以手动执行,因为您只想替换第一个事件。但是正则表达式非常有效,所以不要过早地优化!

        4
  •  5
  •   Beau Grantham    12 年前

    确保也要更换 \s $s 也在替换中。这可能是你想要的,因为你不能有任何子组与你的 () 正在删除)。

    newStr = str.replaceFirst(Pattern.quote(target), Matcher.quoteReplacement(replacement));
    
        5
  •  2
  •   Sirko    11 年前

    Java中的String BuudRead类可以非常容易地使用基于非正则表达式的一个字符串替换另一个字符串。

    private static String replace(String in, String ths, String that) {
    
        StringBuilder sb = new StringBuilder(in);
    
        int idx = sb.indexOf(ths); 
    
        while (idx > -1)
            sb.replace(idx, idx + ths.length(), that);
            idx = sb.indexOf(ths);
        }
    
        return sb.toString(); 
    
    }
    
        6
  •  2
  •   Community CDub    8 年前

    解决方案 Pattern

    你也可以改变 String.replace 使用的方法 字面意义的 只替换第一次出现的字符的解释 target 字符序列:

    /**
     * Replaces the first subsequence of the <tt>source</tt> character sequence
     * that matches the literal target sequence with the specified literal
     * replacement sequence.
     * 
     * @param source source sequence on which the replacement is made
     * @param target the sequence of char values to be replaced
     * @param replacement the replacement sequence of char values
     * @return the resulting string
     */
    private static String replaceFirst1(CharSequence source, CharSequence target, CharSequence replacement) {
        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
            source).replaceFirst(Matcher.quoteReplacement(replacement.toString()));
    }
    


    从文件中 Pattern.LITERAL :

    当指定此标志时,指定模式的输入字符串将被视为一系列文字字符。 输入序列中的元字符或转义序列将没有特殊意义。


    无解决方案 模式

    当然,另一种更有效的方法是 Alex Martelli 提示生成以下功能:

    /**
     * Replaces the first subsequence of the <tt>source</tt> string that matches
     * the literal target string with the specified literal replacement string.
     * 
     * @param source source string on which the replacement is made
     * @param target the string to be replaced
     * @param replacement the replacement string
     * @return the resulting string
     */
    private static String replaceFirst2(String source, String target, String replacement) {
        int index = source.indexOf(target);
        if (index == -1) {
            return source;
        }
    
        return source.substring(0, index)
            .concat(replacement)
            .concat(source.substring(index+target.length()));
    }
    


    时间测量

    基于10次跑步, replaceFirst2 方法执行关于 快5倍 replaceFirst1 方法。我将这两个方法放入循环中,重复100000次,得到以下结果(以毫秒计):

        Method                 Results (in ms)             Average
    replaceFirst1: 220 187 249 186 199 211 172 199 281 199 | 210
    replaceFirst2:  40  39  58  45  48  40  42  42  43  59 |  45
        7
  •  1
  •   trans    12 年前

    pattern.quote在所有情况下似乎都不起作用。try`pattern.quote(“:-)”);