Bagaimana cara mendapatkan karakter n pertama dari string tanpa memeriksa ukuran atau keluar batas?

163

Bagaimana cara mendapatkan nkarakter pertama dari string di Java tanpa melakukan pemeriksaan ukuran terlebih dahulu (inline dapat diterima) atau mempertaruhkan IndexOutOfBoundsException?

antony.trupe
sumber
1
kecuali Anda menangkap pengecualian, saya tidak tahu bagaimana Anda berencana untuk menangani kasus di mana panjang karakter lebih besar dari panjang String.
Matt Boehm
2
Mengapa? Apa keengganan Anda untuk memeriksa panjang atau menangkap pengecualian?
paxdiablo
1
Karena penasaran, mengapa Anda ingin menghindari cek ukuran. Ini bukan C.
Tom Hawtin - tackline
apa yang saya maksudkan adalah keinginan untuk menghindari blok if / else, bukan keengganan untuk benar-benar memeriksa panjang.
antony.trupe
duplikat potensial dari: stackoverflow.com/questions/8499698/…
Mulki

Jawaban:

347

Inilah solusi yang rapi:

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

Opini: sementara solusi ini "rapi", saya pikir itu sebenarnya kurang dapat dibaca daripada solusi yang menggunakan if/ elsedengan cara yang jelas. Jika pembaca belum melihat trik ini, dia harus berpikir lebih keras untuk memahami kode. IMO, makna kode lebih jelas di if/ elseversi. Untuk solusi yang lebih bersih / lebih mudah dibaca, lihat jawaban @ paxdiablo.

Stephen C
sumber
1
+1. Bahkan lebih baik jika ini dibungkus dengan fungsi bernama safe_substring atau substring_safe, seperti jawaban paxdiablo, sehingga penggunaan lebih mudah dibaca / maksud lebih jelas.
ToolmakerSteve
Saya tidak setuju dengan apa yang Anda katakan. Jika ini dibungkus dalam suatu fungsi, tidak masalah apa yang ada di dalam fungsi tersebut , dan "kerapian" apa pun pasti diimbangi oleh kurangnya kejelasan. Inti dari solusi ini adalah "rapi" untuk kasus di mana Anda tidak ingin membuat fungsi wrapper.
Stephen C
88

Jangan menemukan kembali roda ...:

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

Javadoc mengatakan:

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"

Jadi:

StringUtils.substring("abc", 0, 4) = "abc"
Nickkk
sumber
1
Itu tidak menjawab pertanyaan, tetapi terlepas dari itu masih memberikan solusi. Jika OP mampu memahami, saya pikir ini adalah solusi yang lebih baik.
aullah
5
Mungkin bermanfaat juga untuk menunjukkan bahwa StringUtils.substring(yourString, 0, n)tidak sama dengan yourString.substring(0, n). Yang pertama adalah dari StringUtils, sedangkan yang kedua menggunakan String.substring(yang memberikan pengecualian jika indeks akhir melebihi panjang string).
ToolmakerSteve
Sama seperti FYI jika Anda melihat sumber untuk metode ini, penanganannya adalah kasus di mana ujung lebih besar dari panjang dengan mengubah ujung ke panjang:if (end > str.length()) { end = str.length();}
bholl
1
Parameter terakhir StringUtils.substring(String s, int start, int len)adalah tidak len, itu adalah Indeks akhir.
gorootde
StringUtils.substring ("abc", 0, 4) = "abc", bekerja untuk saya. Terima kasih!
Akash5288
42

Apache Commons Lang memiliki StringUtils.leftmetode untuk ini.

String upToNCharacters = StringUtils.left(s, n);
Skuli
sumber
Bukankah ini seharusnya menjadi solusi terbaik? Mengapa tidak banyak memilih ini?
Do Will
3
Mungkin karena orang lain tidak memiliki pendapat yang sama dengan Anda? :-)
Stephen C
jawaban ini datang lebih lambat dari tanggal pertanyaan asli.
Mulki
@DoWill: Karena menambahkan perpustakaan pihak ketiga (lainnya) ke lingkungan Anda yang dapat dieksekusi tidak selalu bermanfaat.
LarsH
12

Ada kelas pertanyaan di SO yang kadang-kadang masuk akal, yang satu ini sangat dekat :-)

Mungkin Anda bisa menjelaskan keengganan Anda untuk menggunakan salah satu dari dua metode yang Anda singkirkan.

Jika itu hanya karena Anda tidak ingin menambahkan kode Anda dengan ifpernyataan atau kode penangkapan pengecualian, salah satu solusinya adalah menggunakan fungsi pembantu yang akan mengurusnya untuk Anda, seperti:

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

yang akan memeriksa panjang sebelumnya dan bertindak sesuai (baik mengembalikan string atau pad yang lebih kecil dengan spasi).

Maka Anda tidak perlu khawatir tentang hal itu dalam kode Anda sama sekali, cukup hubungi:

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

dari pada:

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

Ini akan bekerja jika Anda khawatir (berdasarkan komentar Anda untuk jawaban lain), tidak memutus aliran kode ketika melakukan banyak hal membangun string.

paxdiablo
sumber
1
Anda harus membaca komentar lebih dekat, @antony, terutama yang tersenyum, dan tidak begitu berharga tentang mereka yang mencoba membantu. Saya hanya menyatakan bahwa Anda tidak memberikan alasan mengapa Anda harus menghindari kedua metode ini. Dan ini adalah jawaban yang asli, menggunakan fungsi pembantu, itulah sebabnya tidak ada dalam komentar.
paxdiablo
1
+1: Ini adalah pendekatan JAUH lebih baik daripada yang diterima, mengingat keinginan OP untuk tidak mengacaukan kode. (atau lihat solusi Nickkk untuk menyertakan perpustakaan yang sudah memiliki fungsi yang berperilaku seperti yang diinginkan.)
ToolmakerSteve
12
String upToNCharacters = String.format("%."+ n +"s", str);

Mengerikan jika nadalah variabel (jadi Anda harus membangun string format), tetapi cukup jelas jika konstanta:

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

docs

13rn
sumber
Alternatif yang menarik, meskipun saya tidak bisa membayangkan pernah menggunakannya, mengingat pendekatan yang lebih tradisional, yang diberikan empat tahun lalu.
ToolmakerSteve
Jawaban terbaik karena String input hanya dibaca sekali, jadi tidak perlu menyimpannya dalam variabel, yang memungkinkan untuk menanamkannya dengan rapi.
Profiterole
3

Gunakan metode substring, sebagai berikut:

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

Jika n lebih besar dari panjang string, ini akan menghasilkan pengecualian, seperti yang ditunjukkan oleh seorang komentator. salah satu solusi sederhana adalah dengan membungkus semua ini dalam kondisi if(s.length()<n)di elseklausa Anda, Anda dapat memilih apakah Anda hanya ingin mencetak / mengembalikan seluruh String atau menanganinya dengan cara lain.

Matt Boehm
sumber
1
ini berisiko mendapatkan IndexOutOfBoundsException
antony.trupe
Omong-omong, jika Anda berencana pemrograman di Java, Anda harus mencoba menghafal sebagian besar metode API untuk String ( java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html ).
Matt Boehm
Saya sudah mengesampingkan substring, setidaknya dengan sendirinya, karena bukan jawabannya.
antony.trupe
Anda harus memeriksa ukuran atau menangkap pengecualian. Bolehkah saya bertanya mengapa melakukan salah satu dari ini tidak akan berhasil dalam situasi Anda?
Matt Boehm
3
Bagaimana ini merupakan jawaban untuk pertanyaan itu? Pertanyaannya adalah bertanya bagaimana TIDAK harus melakukan pemeriksaan ukuran terlebih dahulu, atau menyebabkan pengecualian yang perlu ditangkap.
ToolmakerSteve
3

Jika Anda cukup beruntung untuk berkembang bersama Kotlin,
Anda dapat menggunakannya takeuntuk mencapai tujuan Anda.

val someString = "hello"

someString.take(10) // result is "hello"
someString.take(4) // result is "hell" )))
Leo Droidcoder
sumber
0

ApacheCommons mengejutkan saya, StringUtils.abbreviate(String str, int maxWidth)menambahkan "..." tidak ada opsi untuk mengubah postfix. WordUtils.abbreviate(String str, int lower, int upper, String appendToEnd)melihat ke ruang kosong berikutnya.

Saya hanya akan meninggalkan ini di sini:

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;
}
Yuceel
sumber
1
@ VolkanGüven Ini karena kalimat "ApacheCommons mengejutkan saya" ini. Saya melakukan dosa melalui mengkritik perpustakaan ApacheCommons yang suci. Atau apalah ...
yuceel
0

Kotlin: (Jika ada yang butuh)

var mText = text.substring(0, text.length.coerceAtMost(20))
Touhid
sumber