非空字符串中的空字符串[重复]

Posted

技术标签:

【中文标题】非空字符串中的空字符串[重复]【英文标题】:Empty Strings within a non empty String [duplicate] 【发布时间】:2017-06-12 19:59:28 【问题描述】:

我对代码感到困惑

public class StringReplaceWithEmptyString 

    public static void main(String[] args) 
    
        String s1 = "asdfgh";
        System.out.println(s1);
        s1 = s1.replace("", "1");
        System.out.println(s1); 
    

输出是:

asdfgh
1a1s1d1f1g1h1

所以我的第一个意见是字符串中的每个字符在两边都有一个空字符串""。但如果在'a'(在字符串中)之后是这种情况,那么输出的第二行应该有两个'1'(一个用于'a'的结尾,第二个用于's'的开始)。

现在我检查了这些链接In Java, is a String an array of chars? 和String representation in Java 中的字符串是否表示为char[],我得到的答案是YES。

所以我尝试将空字符 '' 分配给 char 变量,但它给了我一个编译器错误,

无效的字符常量

当我在char[] 中尝试时,相同的过程会产生编译器错误

char[] c = '','a','','s';  // CTE

所以我对三件事感到困惑。

    char[] 如何表示空字符串? 为什么我得到上述代码的输出? 第一次初始化时,字符串 s1 在 char[] 中如何表示?

抱歉,如果我的问题的任何部分有误。

【问题讨论】:

我会从 String#replaceAll 预料到这一点,但不会从 String#replace 得到这个 @TimBiegeleisen 刚刚测试过,它实际上只用String#replace 产生了这个结果 "空字符串的表示方式" - char[] empty = ; IMO 询问字符串中有多少个空字符串有点像除以零。 我很惊讶它恰好插入了一个 1 而不是零。毕竟"ab" == "a" + "" + "b" == "a" + "" + "" + "b"等等;所以说它们之间有 1 空字符串似乎......任意。 【参考方案1】:

只是为 Tim Biegeleisen 的答案添加更多解释。

从 Java 8 开始,java.lang.String 类中replace 方法的代码是

public String replace(CharSequence target, CharSequence replacement) 
        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
                this).replaceAll(Matcher.quoteReplacement(replacement.toString()));

在这里您可以清楚地看到字符串被正则表达式模式匹配器替换,并且在正则表达式中“”由零长度字符标识,并且它存在于任何非零长度字符周围。

所以,你的代码在后台执行如下

Pattern.compile("".toString(), Pattern.LITERAL).matcher("asdfgh").replaceAll(Matcher.quoteReplacement("1".toString()));

输出变成

1a1s1d1f1g1h1

【讨论】:

感谢侦探工作+1【参考方案2】:

根据 Andy Turner 的精彩评论,您对 String#replace() 的调用实际上是使用 String#replaceAll() 实现的。因此,这里发生了正则表达式替换。匹配出现在第一个字符之前、字符串中每个字符之间以及最后一个字符之后。

^|a|s|d|f|g|h|$
 ^ this and every pipe matches to empty string ""

您进行的匹配是零长度匹配。在String.replaceAll() 中使用的Java 正则表达式实现中,其行为如上例所示,即匹配每个字符间位置以及第一个字符之前和最后一个字符之后的位置。

这是一个更详细地讨论零长度匹配的参考:http://www.regexguru.com/2008/04/watch-out-for-zero-length-matches/

零宽度或零长度匹配是不匹配任何字符的正则表达式匹配。它只匹配字符串中的一个位置。例如。正则表达式 \b 匹配 1 和 , 之间的 1,2。

【讨论】:

我想我们都可以看到,但问题是为什么会发生这种情况?在字符之间有一个空的String 的目的是什么?或者这可能是String#replace() 方法的错误? 那么 @Tim Biegeleisen 首次初始化字符串 s1 时的 char[] 表示形式是什么 但是根据它的 JavaDoc,主题中的方法 (String.replace(CharSequence, CharSequence)) 实际上不应该在不使用正则表达式的情况下进行匹配吗? replaceAll 方法确实使用了正则表达式,它在其 JavaDoc 中声明了这一点,但 replace(CharSequence, CharSequence) 并没有在任何地方提到正则表达式,它实际上说 替换此字符串中与 literal 匹配的每个子字符串目标序列... .这就是让我感到困惑的原因。 @SantiBailors 是的,我也是这么想的。 Google 的 Java 架构师 Andy Turner 似乎认为 replaceAll 正在被使用。在任何情况下,行为都是零长度的正则表达式替换。 ^$ 表示 entire 字符串中没有任何内容,因此只有空字符串匹配。搜索"" unbounded 意味着找到字符串中每个字符之间的边界。有意义吗?【参考方案3】:

这是因为它对您传递给 replace() 的模式/替换进行正则表达式匹配。

 public String replace(CharSequence target, CharSequence replacement) 
    return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
     this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
 

替换此字符串中与文字目标匹配的每个子字符串 具有指定文字替换序列的序列。这 替换从字符串的开头到结尾进行,对于 例如,将字符串“aaa”中的“aa”替换为“b”将导致 “ba”而不是“ab”。

参数:

target char 值的序列 被替换

replacement char值的替换顺序

返回:结果字符串

抛出:NullPointerException 如果是目标 或替换为空。

因为: 1.5

请在下面的链接阅读更多...(也可以浏览源代码)。

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String.replace%28java.lang.CharSequence%2Cjava.lang.CharSequence%29

诸如“”之类的正则表达式将匹配字符串中所有可能的空字符串。在这种情况下,它恰好是开头和结尾以及字符串中每个字符之后的每个空格。

【讨论】:

你引用中的文档引用了哪种方法(围绕给定正则表达式的匹配拆分此字符串...)? 抱歉,错误(仓促)复制和粘贴。更正。 谢谢,现在是replace(CharSequence, CharSequence) 的JavaDoc。这突出了问题(在我看来):该方法的文档根本没有提到与正则表达式匹配,而replaceAll 的文档却提到了。

以上是关于非空字符串中的空字符串[重复]的主要内容,如果未能解决你的问题,请参考以下文章

回文串[APIO2014](回文树)

字符串

P3649 [APIO2014]回文串(回文树)

串文档之串

钥匙串中存储的字符串是不是有长度限制?

字符串匹配算法 - BM算法