2012-07-06 24 views
8

Tôi có đoạn code sau đây, mà làm việc, nhưng tôi tự hỏi nếu có một cách "groovier" để làm điều này:Có cách nào khác để thêm dấu gạch ngang vào chuỗi không?

/** 
    * 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 
    } 
} 

Trả lời

2

Dunno nếu tôi thích điều này bất kỳ tốt hơn. Tôi cũng làm cho bản đồ vị trí là một kết thúc tĩnh.

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

Phạm vi làm cho một chút ít lộn xộn, IMO:

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

Với một bơm-với-hai-ắc nó phải được dễ dàng để làm một phiên bản list-of-dash-vị trí, quá .

+0

Bạn có thể giải thích * nó một phần? * Làm gì trong trường hợp đó? – Gregg

+0

@Gregg Nó de-cấu trúc mảng vì vậy nó trông giống như hai tham số chuỗi con cá nhân. Nó sẽ làm việc mà không có nó, mặc dù, tôi nghĩ. Tôi không thể cho bạn biết tại sao nó sẽ, mặc dù, đó là lý do tại sao tôi là gà và để nó trong. –

8

Trước tiên, bạn có thể sử dụng toán tử chuỗi [] để lấy các bản chất thay vì substring và thả các biến trung gian. Ví dụ: trong trường hợp cho length == 10:

"${isbn[0]}-${isbn[1..6]}-${isbn[7..8]}-${isbn[9]}" 

Bây giờ, có một chút lặp lại ở đó. Bạn có thể nhận thay vì đầu tiên nhận được tất cả các isbn phân đoạn và sau đó .join chúng với '-':

[isbn[0], isbn[1..6], isbn[7..8], isbn[9]].join('-') 

Và, hơn nữa, thay vì tham khảo isbn mọi thời gian, bạn có thể tạo ra một danh sách các phạm vi bạn muốn nhận được và sau đó nhận được tất cả đồng thời sử dụng collect:

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

Nếu bạn đang đi cho mã chơi golf, bạn cũng có thể làm:

('-'+isbn)[1, 0, 2..7, 0, 8..9, 0, 10] 

Tôi sẽ để nó cho bạn để tìm ra cách thức hoạt động, nhưng tôi đoán có lẽ không phải là một ý tưởng tốt để để lại điều đó trên mã sản xuất, trừ khi bạn muốn gây bất ngờ cho các nhà bảo trì tương lai hehe.


Ngoài ra, hãy chú ý rằng các định dạng khi length == 13 cũng giống như đối với length == 10 nhưng với một tiền tố khác nhau, bạn có thể tái sử dụng các chức năng tương tự trong trường hợp đó. Toàn bộ chức năng (với một vài bài kiểm tra) sẽ là:

/** 
* 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' 

Bây giờ, tôi nghĩ rằng có một số mùi hôi trong mã đó. Có thể isbnnull? Ít nhất với tôi, điều này không giống như một hàm cần phải bận tâm về sự vô hiệu của đối số của nó, hoặc ít nhất nó không rõ ràng bằng cách đọc tên của nó (nó phải được gọi là formatIsbnOrNull thay thế nếu cả hai chuỗi ISBN và giá trị null được cháp nhận). Nếu giá trị null không hợp lệ, sau đó để cho nó nổ tung với một NullPointerException khi truy cập isbn.length() để người gọi biết rằng họ đã vượt qua một đối số sai, thay vì âm thầm trả về cùng một giá trị rỗng.

Tương tự như vậy đối với số return ISBN ở cuối. Nó có được mong đợi cho chức năng đó để nhận một chuỗi dài 10 ký tự không? Nếu không, tốt hơn throw new IllegalArgumentException() và để cho người gọi biết họ đã gọi sai.


Cuối cùng, tôi không chắc đây có phải là giải pháp "dễ đọc" nhất hay không. Một giải pháp khả thi khác là có chuỗi cho định dạng, như '###-#-######-##-#' và sau đó thay thế # s theo các ký tự isbn. Tôi nghĩ rằng nó có thể có nhiều tự chủ tài liệu:

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

Điều này là tất cả tuyệt vời. Cảm ơn các câu trả lời chi tiết. Tôi không chắc phải đi đâu. Nếu tôi kết thúc bằng cách sử dụng của bạn, tôi sẽ thay đổi câu trả lời được chấp nhận của tôi. – Gregg

+0

Tôi nghĩ rằng cái cuối cùng là tốt nhất, nếu một chút mờ đục - nhưng IMO thì không một người bảo trì nào quan tâm đến bất cứ điều gì ngoại trừ các mẫu, nếu như vậy. Các giải pháp phạm vi là như nhau; Tôi không thể quyết định cái nào tôi thích hơn giữa mẫu/dãy. –

+0

@Gregg Một khả năng khác mà tôi không đề cập ở đây là tạo một hàm chung 'phân vùng (str, kích cỡ)' lấy một chuỗi và trả về một danh sách các chuỗi con có kích thước nhất định (ví dụ: 'partition ('hello', [ 4, 1]) == ['địa ngục', 'o'] ') để sau đó nhận được ISBN có thể được diễn tả là" phân vùng chuỗi gốc lấy 1, 6, 2 và 1 ký tự và nối chúng với dấu gạch ngang ":' phân vùng (isbn, [1, 6, 2, 1]). tham gia ('-') '. Phải mất một chút mã hóa mà chức năng chung, nhưng việc thực hiện 'formatIsbn' được rất gia tộc :) – epidemian

3

tôi sẽ cố gắng sử dụng Regex ... Tôi nghĩ đó là khá nhiều có thể đọc được nếu bạn biết làm thế nào để sử dụng regex, và đó là javascript lấy cảm hứng từ cú pháp trong groovy là khá mát mẻ cũng .

Một điều nữa: nó khá rõ ràng, nhìn vào các nhóm chụp, chuỗi của bạn trông như thế nào cho định dạng mong muốn.

private formatISBN(String isbn) { 
    if (isbn?.length() == 10) { 
     m = isbn =~ /(\d{1})(\d{6})(\d{2})(\d{1})/ 
     return "${m[0][1]}-${m[0][2]}-${m[0][3]}-${m[0][4]}" 
    } else if (isbn?.length() == 13) { 
     m = isbn =~ /(\d{3})(\d{1})(\d{6})(\d{2})(\d{1})/ 
     return "${m[0][1]}-${m[0][2]}-${m[0][3]}-${m[0][4]}-${m[0][5]}"   
    } else { 
     return isbn 
    } 
} 

Btw, @epidemian đề xuất sử dụng backreferences rất tuyệt! Tôi nghĩ mã sẽ trông giống như:

private formatISBN(String isbn) { 
    if (isbn?.length() == 10) { 
     return isbn.replaceAll(/(\d{1})(\d{6})(\d{2})(\d{1})/, '$1-$2-$3-$4') 
    } else if (isbn?.length() == 13) { 
     return isbn.replaceAll(/(\d{3})(\d{1})(\d{6})(\d{2})(\d{1})/, '$1-$2-$3-$4-$5') 
    } else { 
     return isbn 
    } 
} 
+1

Tôi thực sự thích regex trong trường hợp này; nó rất dễ đọc! Nhưng tôi nghĩ rằng phần thay thế là quá lặp đi lặp lại. Có lẽ bạn có thể sử dụng một cái gì đó như '(isbn = ~/(\ d {1}) (\ d {6}) (\ d {2}) (\ d {1}) /) [0] .tail(). join ('-') ', hoặc' isbn.replaceAll (/ (\ d {1}) (\ d {6}) (\ d {2}) (\ d {1}) /, '$ 1- $ 2- $ 3- $ 4 ') '? = D – epidemian

+0

Whoa, 'isbn.replaceAll (/ (\ d {1}) (\ d {6}) (\ d {2}) (\ d {1}) /, '$ 1- $ 2- $ 3- $ 4') 'rất rất thông minh: D – everton

+0

Không có tham chiếu ngược tôi thực sự không thích giải pháp regex, thành thật - ngay cả với, tôi thấy mã khó nhìn từ quan điểm thẩm mỹ. –

4

Xem xét thêm phương thức vào lớp Chuỗi, như được hiển thị ở đây. Lưu ý rằng câu trả lời này là một spin trên một gợi ý thông minh trong câu trả lời của epidemian (re: collect).

Lưu ý:

Mã này augments String với asIsbn().

Phạm vi [0..2] không cần gọi đến asIsbn(), nhưng đối xứng sử dụng collect hai lần không thể cưỡng lại.

Groovy trả về biểu hiện cuối cùng trong if/else, vì vậy 'trở lại' là không cần thiết

/** 
* 10 digit - #-######-##-# 
* 13 digit - ###-#-######-##-# 
**/ 
String.metaClass.asIsbn = { -> 
    if (delegate.length() == 10) { 
     [0, 1..6, 7..8, 9].collect { delegate[it] }.join('-') 
    } else if (delegate.length() == 13) { 
     [0..2, 3..12].collect { delegate[it].asIsbn() }.join('-') 
    } else { 
     delegate 
    } 
} 

assert "abcdefghij".asIsbn() == 'a-bcdefg-hi-j' 
assert "abcdefghijklm".asIsbn() == 'abc-d-efghij-kl-m' 
assert "def".asIsbn() == "def" 
String s = null 
assert s?.asIsbn() == null 
+1

+1 cho _sexiness_ của '[0..2, 3..12] .collect {delegate [it] .asIsbn()}' = D – epidemian

Các vấn đề liên quan