Làm cách nào để có được n ký tự đầu tiên của chuỗi mà không kiểm tra kích thước hoặc đi ra khỏi giới hạn?


163

Làm cách nào để tôi có được các nký tự đầu tiên của chuỗi trong Java mà không thực hiện kiểm tra kích thước trước (nội tuyến có thể chấp nhận được) hoặc mạo hiểm IndexOutOfBoundsException?


1
trừ khi bạn bắt được ngoại lệ, tôi không biết bạn dự định xử lý trường hợp độ dài ký tự lớn hơn độ dài Chuỗi.
Matt Boehm

2
Tại sao? Bạn có ác cảm gì khi kiểm tra độ dài hoặc bắt ngoại lệ?
paxdiablo

1
Vì tò mò, tại sao bạn muốn tránh việc kiểm tra kích thước. Đây không phải là C.
Tom Hawtin - tackline

những gì tôi muốn bày tỏ là mong muốn tránh một khối if / khác, không ác cảm với việc kiểm tra độ dài thực sự.
antony.trupe

bản sao tiềm năng của: stackoverflow.com/questions/8499698/
Mạnh

Câu trả lời:


347

Đây là một giải pháp gọn gàng:

String upToNCharacters = s.substring(0, Math.min(s.length(), n));

Ý kiến: trong khi giải pháp này là "gọn gàng", tôi nghĩ rằng nó thực sự khó đọc hơn một giải pháp sử dụng if/ elsetheo cách rõ ràng. Nếu người đọc chưa thấy thủ thuật này, anh ta / cô ta phải suy nghĩ kỹ hơn để hiểu mã. IMO, ý nghĩa của mã rõ ràng hơn trong phiên bản if/ else. Để biết giải pháp sạch hơn / dễ đọc hơn, hãy xem câu trả lời của @ paxdiablo.


1
+1. Thậm chí tốt hơn nếu điều này được bao bọc trong một hàm có tên safe_subopes hoặc sub chuỗi_safe, như câu trả lời của paxdiablo, để việc sử dụng dễ đọc / có ý định rõ ràng hơn.
ToolmakerSteve

Tôi không đồng ý với những gì bạn đang nói. Nếu điều này được bao bọc trong một chức năng, thì không có vấn đề gì bên trong chức năng và bất kỳ "sự gọn gàng" nào chắc chắn sẽ bị đè nặng bởi sự thiếu rõ ràng. Điểm chính của giải pháp này là "gọn gàng" cho trường hợp bạn không muốn tạo chức năng bao bọc.
Stephen C

88

Đừng phát minh lại bánh xe ...:

org.apache.commons.lang.StringUtils.substring(String s, int start, int len)

Javadoc nói:

StringUtils.substring(null, *, *)    = null
StringUtils.substring("", * ,  *)    = "";
StringUtils.substring("abc", 0, 2)   = "ab"
StringUtils.substring("abc", 2, 0)   = ""
StringUtils.substring("abc", 2, 4)   = "c"
StringUtils.substring("abc", 4, 6)   = ""
StringUtils.substring("abc", 2, 2)   = ""
StringUtils.substring("abc", -2, -1) = "b"
StringUtils.substring("abc", -4, 2)  = "ab"

Như vậy:

StringUtils.substring("abc", 0, 4) = "abc"

1
Nó không trả lời câu hỏi, nhưng bất kể nó vẫn cung cấp giải pháp. Nếu OP có thể hiểu, tôi nghĩ đây là một giải pháp tốt hơn.
aullah

5
Nó cũng có thể hữu ích để chỉ ra rằng StringUtils.substring(yourString, 0, n)nó không giống như yourString.substring(0, n). Cái trước là từ StringUtils, trong khi cái sau đang sử dụng String.substring(sẽ đưa ra ngoại lệ nếu chỉ số kết thúc vượt quá độ dài chuỗi).
ToolmakerSteve

Cũng giống như FYI nếu bạn tìm trong nguồn cho phương pháp này, nó xử lý trường hợp kết thúc lớn hơn độ dài bằng cách thay đổi kết thúc thành chiều dài:if (end > str.length()) { end = str.length();}
bholl

1
Thông số cuối cùng StringUtils.substring(String s, int start, int len)không phải là len, đó là Chỉ số kết thúc.
gorootde

StringUtils.subopes ("abc", 0, 4) = "abc", đã làm việc cho tôi. Cảm ơn !
Akash5288

42

Apache Commons Lang có một StringUtils.leftphương pháp cho việc này.

String upToNCharacters = StringUtils.left(s, n);

Đây không phải là giải pháp tốt nhất sao? Tại sao không có nhiều người bỏ phiếu này?
Làm Will

3
Có lẽ bởi vì những người khác không có cùng quan điểm với bạn? :-)
Stephen C

câu trả lời này đến muộn hơn nhiều so với ngày hỏi ban đầu.
Mulki

@DoWill: Bởi vì việc thêm một thư viện bên thứ 3 (khác) vào môi trường thực thi của bạn không phải lúc nào cũng đáng giá.
LarsH

12

Có một lớp câu hỏi về SO đôi khi không có ý nghĩa hoàn hảo, câu hỏi này rất gần gũi :-)

Có lẽ bạn có thể giải thích ác cảm của mình với việc sử dụng một trong hai phương pháp mà bạn đã loại trừ.

Nếu đó chỉ là vì bạn không muốn lấy mã của mình bằng các ifcâu lệnh hoặc mã bắt ngoại lệ, thì một giải pháp là sử dụng hàm trợ giúp sẽ chăm sóc nó cho bạn, đại loại như:

static String substring_safe (String s, int start, int len) { ... }

sẽ kiểm tra độ dài trước và hành động tương ứng (trả về chuỗi nhỏ hơn hoặc phần đệm có dấu cách).

Sau đó, bạn không phải lo lắng về nó trong mã của bạn, chỉ cần gọi:

String s2 = substring_safe (s, 10, 7);

thay vì:

String s2 = s.substring (10,7);

Điều này sẽ hoạt động trong trường hợp bạn có vẻ lo lắng (dựa trên nhận xét của bạn cho các câu trả lời khác), không phá vỡ dòng mã khi thực hiện nhiều công cụ xây dựng chuỗi.


1
Bạn nên đọc bình luận kỹ hơn, @antony, đặc biệt là mặt cười và không quá quý giá về những người cố gắng giúp đỡ. Tôi chỉ đơn thuần nói rằng bạn đã không đưa ra bất kỳ lý do nào cho lý do tại sao bạn phải tránh hai phương pháp. Và đây là một câu trả lời chính hãng, sử dụng chức năng của người trợ giúp, đó là lý do tại sao nó không có trong một nhận xét.
paxdiablo

1
+1: Đây là một cách tiếp cận tốt hơn nhiều so với cách tiếp cận được chấp nhận, với mong muốn của OP không làm lộn xộn mã. (hoặc xem giải pháp của Nickkk bao gồm một thư viện đã có chức năng hoạt động như mong muốn.)
ToolmakerSteve

12
String upToNCharacters = String.format("%."+ n +"s", str);

Awful if nlà một biến (vì vậy bạn phải xây dựng chuỗi định dạng), nhưng khá rõ ràng nếu là hằng số:

String upToNCharacters = String.format("%.10s", str);

tài liệu


Sự thay thế thú vị, mặc dù tôi không thể tưởng tượng được việc sử dụng nó, với những cách tiếp cận truyền thống hơn, đã được đưa ra bốn năm trước.
ToolmakerSteve

Câu trả lời tốt nhất vì Chuỗi đầu vào chỉ được đọc một lần, do đó không cần lưu trữ nó trong một biến, điều này giúp có thể nhúng nó gọn gàng.
Profiterole

3

Sử dụng phương pháp chuỗi con, như sau:

int n = 8;
String s = "Hello, World!";
System.out.println(s.substring(0,n);

Nếu n lớn hơn độ dài của chuỗi, điều này sẽ đưa ra một ngoại lệ, như một người bình luận đã chỉ ra. Một giải pháp đơn giản là bọc tất cả điều này trong điều kiện if(s.length()<n)trong elsemệnh đề của bạn , bạn có thể chọn xem bạn chỉ muốn in / trả lại toàn bộ Chuỗi hay xử lý theo cách khác.


1
rủi ro này nhận được IndexOutOfBoundException
antony.trupe

Nhân tiện, nếu bạn có kế hoạch lập trình bằng Java, bạn nên cố gắng ghi nhớ hầu hết các phương thức API cho Chuỗi ( java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html ).
Matt Boehm

Tôi đã loại trừ chuỗi con, ít nhất là chính nó, không phải là câu trả lời.
antony.trupe

Bạn phải kiểm tra kích thước hoặc bắt ngoại lệ. Tôi có thể hỏi tại sao làm một trong những điều này sẽ không làm việc trong tình huống của bạn?
Matt Boehm

3
Làm thế nào đây là một câu trả lời cho câu hỏi? Câu hỏi đặt ra là làm thế nào để KHÔNG phải kiểm tra kích thước trước, cũng không gây ra ngoại lệ cần phải bắt.
ToolmakerSteve

3

Nếu bạn đủ may mắn để phát triển với Kotlin,
bạn có thể sử dụng takeđể đạt được mục tiêu của mình.

val someString = "hello"

someString.take(10) // result is "hello"
someString.take(4) // result is "hell" )))

0

ApacheCommons làm tôi ngạc nhiên, StringUtils.abbreviate(String str, int maxWidth)thêm "..." không có tùy chọn để thay đổi hậu tố. WordUtils.abbreviate(String str, int lower, int upper, String appendToEnd)nhìn lên không gian trống tiếp theo.

Tôi sẽ rời khỏi đây:

public static String abbreviate(String s, int maxLength, String appendToEnd) {
    String result = s;
    appendToEnd = appendToEnd == null ? "" : appendToEnd;
    if (maxLength >= appendToEnd.length()) {
        if (s.length()>maxLength) {
            result = s.substring(0, Math.min(s.length(), maxLength - appendToEnd.length())) + appendToEnd;
        }
    } else {
        throw new StringIndexOutOfBoundsException("maxLength can not be smaller than appendToEnd parameter length.");
    }
    return result;
}

1
@ VolkanGüven Đó là vì câu "ApacheCommons này làm tôi ngạc nhiên". Tôi đã phạm tội thông qua thư viện thánh ApacheCommons. Hoặc bất cứ điều gì ...
yuceel

0

Kotlin: (Nếu ai cần)

var mText = text.substring(0, text.length.coerceAtMost(20))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.