是否有一种Groovier方法将字符串添加到字符串?

Gre*_*egg 8 string groovy

我有以下代码,这是有效的,但我想知道是否有一种"groovier"方式这样做:

/**
   * 10 digit - #-######-##-#
   * 13 digit - ###-#-######-##-#
   * */
private formatISBN(String isbn) {
  if (isbn?.length() == 10) {
    def part1 = isbn.substring(0, 1)
    def part2 = isbn.substring(1, 7)
    def part3 = isbn.substring(7, 9)
    def part4 = isbn.substring(9, 10)
    return "${part1}-${part2}-${part3}-${part4}"
  } else if (isbn?.length() == 13) {
    def part1 = isbn.substring(0, 3)
    def part2 = isbn.substring(3, 4)
    def part3 = isbn.substring(4, 10)
    def part4 = isbn.substring(10, 12)
    def part5 = isbn.substring(12, 13)
    return "${part1}-${part2}-${part3}-${part4}-${part5}"
  } else {
    return isbn
  }
}
Run Code Online (Sandbox Code Playgroud)

epi*_*ian 8

您可以先使用[]字符串运算符来获取子字符串,而不是substring删除中间变量.例如,在以下情况下length == 10:

"${isbn[0]}-${isbn[1..6]}-${isbn[7..8]}-${isbn[9]}"
Run Code Online (Sandbox Code Playgroud)

现在,那里有一些重复.您可以首先获取所有isbn细分,然后.join使用'-':

[isbn[0], isbn[1..6], isbn[7..8], isbn[9]].join('-')
Run Code Online (Sandbox Code Playgroud)

而且,更进一步,isbn您可以列出您想要获得的范围,而不是每次都参考,然后使用collect以下方法同时获取它们:

[0, 1..6, 7..8, 9].collect { isbn[it] }.join('-')
Run Code Online (Sandbox Code Playgroud)

如果您打算打高尔夫球,您还可以:

('-'+isbn)[1, 0, 2..7, 0, 8..9, 0, 10]
Run Code Online (Sandbox Code Playgroud)

我会留给你弄清楚它是如何工作的,但我想将它留在生产代码上可能不是一个好主意,除非你想让未来的维护者感到惊讶.


另外,请注意,格式何时length == 13与for length == 10具有相同但具有不同的前缀,然后您可以在该情况下重用相同的函数.整个功能(有几个测试)将是:

/**
 * 10 digit - #-######-##-#
 * 13 digit - ###-#-######-##-#
 **/
def formatIsbn(isbn) {
    switch (isbn?.length()) {
        case 10: return [0, 1..6, 7..8, 9].collect { isbn[it] }.join('-')
        case 13: return isbn.take(3) + '-' + formatIsbn(isbn.drop(3))
        default: return isbn
    }
}

assert formatIsbn('abcdefghij') == 'a-bcdefg-hi-j'
assert formatIsbn('abcdefghijklm') == 'abc-d-efghij-kl-m'
Run Code Online (Sandbox Code Playgroud)

现在,我认为该代码中有一些难闻的气味.能isbnnull?至少在我看来,这看起来不像是一个需要打扰其论证的无效性的函数,或者至少通过读取它的名称并不清楚(formatIsbnOrNull如果ISBN字符串和空值都是公认).如果null值无效,那么让它NullPointerException在访问时爆炸,isbn.length()以便调用者知道他们已经传递了错误的参数,而不是静默地返回相同的null.

最后也是如此return ISBN.是否希望该函数接收一个既不是10个也不是13个字符的字符串?如果不是,那就更好了throw new IllegalArgumentException(),让来电者知道他们错误地拨了电话.


最后,我不确定这是否是最"可读"的解决方案.另一种可能的解决方案是使用格式的字符串'###-#-######-##-#',然后用字符替换#s isbn.我认为它可能更自我记录:

def formatIsbn(isbn) {
    def format = [
        10: '#-######-##-#',
        13: '###-#-######-##-#'
    ][isbn.length()]
    def n = 0
    format.replaceAll(/#/) { isbn[n++] }
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*ton 2

不知道我是否更喜欢这个。我也会将位置图设为静态最终图。

private isbnify(String isbn) {
  def dashesAt = [ 10: [[0,1], [1,7], [7,9],  [9,10]],
                   13: [[0,3], [3,4], [4,10], [10,12], [12,13]]]
  def dashes = dashesAt[isbn?.length()]
  (dashes == null) ? isbn 
                   : dashes.collect { isbn.substring(*it) }.join('-')
}
Run Code Online (Sandbox Code Playgroud)

在我看来,范围可以减少混乱:

private isbnify3(String isbn) {
  def dashesAt = [ 10: [0, 1..6, 7..8, 9],
                   13: [0..2, 3, 4..9, 10..11, 12]]
  def dashes = dashesAt[isbn?.length()]
  dashes == null ? isbn : dashes.collect { isbn[it] }.join("-")
}
Run Code Online (Sandbox Code Playgroud)

使用带有两个累加器的注入,也应该很容易制作破折号位置列表版本。