Fencepost 问题的优雅解决方案(使用字符串)

Posted

技术标签:

【中文标题】Fencepost 问题的优雅解决方案(使用字符串)【英文标题】:Elegant Solutions to the Fencepost Problem (with Strings) 【发布时间】:2011-10-15 00:14:28 【问题描述】:

我指的是将Strings与中间的某个String连接起来,比如用句点分隔的句子连接起来,或者用逗号连接参数列表。我知道您可以使用库,但有时这些库无法满足您的需求,例如当您想要生成要连接的短语时。到目前为止,我已经提出了两个解决方案,

StringBuffer sentence = new StringBuffer();
String period = "";
for ( int i = 0; i < sentences.length; i++ ) 
    sentence.append( period + sentences[i] );
    period = ". ";

遭受period 的冗余重新分配。还有

StringBuffer actualParameters = new StringBuffer();
actualParameters.append( parameters[0] );
for ( int i = 1; i < parameters.length; i++ ) 
    actualParameters.append( ", " + parameters[i] );

删除了重新分配,但看起来仍然没有吸引力。非常感谢任何其他解决方案。

【问题讨论】:

【参考方案1】:

似乎是一个常见问题!

Remove last character of a StringBuilder?

这会导致类似:

StringBuffer sentence = new StringBuffer();
String separator = ", ";
for ( int i = 0; i < sentences.length; i++ ) 
    sentence.append( sentences[i] )
    sentence.append( separator );

sentence.setLength(sentence.length() - separator.length());

【讨论】:

+1 非常好的解决方案,需要不断的时间,跳出框框思考:)(sb 需要替换为sentence)感谢您的链接。 如果您已经在使用 StringBuffer,请不要使用 +!使用第二个append!使用 StringBuffer 的主要原因是避免 + 会创建一个额外的 StringBuffer(每次交互)。 如果sentences 为空,则会崩溃【参考方案2】:

如果你至少有一个字符串,那么:

String join(String separator, String... strings)

    String s = strings[0];
    for (int i = 1; i < strings.length; i++) 
        s += separator + strings[i]; 
    
    return s;

【讨论】:

这实际上与我提出的第二个解决方案相同,只是它使用String 连接来建立结果,尽管由于其他 cmets 中概述的原因,不建议这样做,特别是由 Carlos Heuberger 制作。 现代 Java 编译器将字符串连接转换为 StringBuilder + append() 调用。尝试在类上使用 javap -c 来查看生成的代码。虽然这并不总是像手动生成的代码那样高效,但总是具有更易于遵循源代码的好处。【参考方案3】:

有一个family of functions in Apache Commons Lang that does just that。

如果非得自己写代码,我通常做这种事情的方式如下:

StringBuilder sb = new StringBuilder();
for (String sentence : sentences) 
    if (sb.length() != 0) 
        sb.append(". ");
    
    sb.append(sentence);

此版本允许sentences 是任何可迭代的(返回字符串)。还要注意使用StringBuilder 而不是StringBuffer

很容易将其概括为类似于org.apache.commons.lang.StringUtils.join

【讨论】:

这是一个很好的解决方案,使用了我没有考虑过的扩展 for 循环,谢谢。 这是一个非常好的解决方案,目前为止最好【参考方案4】:
public String join(String sep, String... parts) 
  boolean first = true;
  final StringBuilder sb = new StringBuilder();
  for(String part: parts) 
    if(first)
      first = false;
    else
      sb.append(sep);
    sb.append(part);
  

不要因为不必要的同步和“+”运算符而使用 StringBuffer,因为这会创建不必要的中间 String 对象。

【讨论】:

+1 表示 StringBuffer 和 "+" 运算符的信息,-1 表示代码。它再次受到其他两个答案所具有的额外条件的额外复杂性的影响......

以上是关于Fencepost 问题的优雅解决方案(使用字符串)的主要内容,如果未能解决你的问题,请参考以下文章

消息中字符串的优雅解决方案

优雅的字符串解析解决方案

如何将字符串向量内爆成字符串(优雅的方式)

优雅单测-3用Mockito轻松解决复杂的依赖问题

使用 Kotlin 验证密码 [重复]

使用集合代替桌子(或其他优雅的解决方案)