Bir dizenin ilk n karakterini boyutunu kontrol etmeden veya sınır dışına çıkmadan nasıl alabilirim?


163

Önce nbir boyut denetimi yapmadan (satır içi kabul edilebilir) veya bir riske girmeden Java'da bir dizenin ilk karakterlerine nasıl ulaşabilirim IndexOutOfBoundsException?


1
istisna yakalamak sürece, karakter uzunluğu Dize uzunluğundan daha büyük olduğu durumda nasıl ele alacağınızı bilmiyorum.
Matt Boehm

2
Neden? Uzunluğu kontrol etme veya bir istisna yakalama konusundaki isteksizliğiniz nedir?
paxdiablo

1
Merak, neden boyut kontrolünden kaçınmak istiyorsunuz? Bu C. değil
Tom Hawtin - taktik

ifade etmek istediğim aslında uzunluğunu kontrol etmek için bir istek değil, bir if / else bloğundan kaçınma arzusuydu.
antony.trupe

Yanıtlar:


347

İşte düzgün bir çözüm:

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

Fikir: Bu çözüm "temiz" olsa da, aslında / bariz şekilde kullanan bir çözümden daha az okunabilir olduğunu düşünüyorum . Okuyucu bu hileyi görmediyse , kodu anlamak için daha fazla düşünmek zorundadır . IMO, kodun anlamı / sürümünde daha belirgindir . Daha temiz / daha okunabilir bir çözüm için @ paxdiablo'nun cevabına bakınız.ifelseifelse


1
+1. Bu, paxdiablo'nun yanıtı gibi safe_substring veya substring_safe adlı bir işleve sarılırsa daha iyi olur, böylece kullanım daha kolay okunur / istenir.
ToolmakerSteve

Söylediklerine katılmıyorum. Bu bir işleve sarılırsa, işlevin içinde ne olduğu önemli değildir ve herhangi bir "düzgünlük" netlik eksikliği nedeniyle kesinlikle daha fazla tartılır. Bu çözümün noktası Eğer durum için "temiz" olmasıdır yok bir sarmalayıcı işlevi oluşturmak istiyorum.
Stephen C

88

Tekerleği yeniden icat etmeyin ...:

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

Javadoc diyor ki:

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"

Böylece:

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

1
Soruyu cevaplamıyor, ancak yine de çözüm sağlıyor. Eğer OP anlayabiliyorsa, bunun daha iyi bir çözüm olduğunu düşünüyorum.
aullah

5
Bunun aynı StringUtils.substring(yourString, 0, n)olmadığını belirtmek de yararlı olabilir yourString.substring(0, n). Birincisi StringUtils, ikincisi kullanırken String.substring(son dizin dize uzunluğunu aşarsa istisna verir).
ToolmakerSteve

Bu yöntem için kaynağa bakarsanız FYI gibi, ucunu uzunluğa değiştirerek ucun uzunluğundan daha büyük olduğu durumu ele if (end > str.length()) { end = str.length();}
alırsa

1
Son parametresi StringUtils.substring(String s, int start, int len)len değil, son Dizindir.
gorootde

StringUtils.substring ("abc", 0, 4) = "abc", benim için çalıştı. Teşekkürler !
Akash5288

42

Apache Commons Lang'ın bunun için bir StringUtils.leftyöntemi var.

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

Bu en iyi çözüm olmamalı mı? Neden bu kadar çok oylama yapılmıyor?
Do Will

3
Belki başkaları sizinle aynı görüşe sahip olmadığından? :-)
Stephen C

bu cevap orijinal soru sorma tarihinden çok daha geç geldi.
Mulki

@DoWill: Çünkü yürütülebilir ortamınıza (diğer) bir üçüncü taraf kitaplığı eklemek her zaman faydalı değildir.
LarsH

12

SO'da bazen mükemmel anlamda daha az anlam ifade eden bir soru sınıfı var, bu tehlikeli bir şekilde yakın :-)

Belki de, dışladığınız iki yöntemden birini kullanmaktan kaçınmayı açıklayabilirsiniz.

Kodunuzu ififadelerle veya istisna kodu yakalayarak istemiyorsanız , çözümlerden biri sizin için bununla ilgilenecek bir yardımcı işlev kullanmaktır:

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

uzunlukları önceden kontrol eder ve buna göre hareket eder (boşluklu daha küçük dize veya ped döndürür).

O zaman kodunuzda endişelenmenize gerek yok, sadece arayın:

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

onun yerine:

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

Bu, çok sayıda dize oluşturma işi yaparken kodun akışını kırmamaktan endişe duyduğunuzda (diğer yanıtlara yaptığınız yorumlara dayanarak) çalışmanız durumunda işe yarar.


1
Yorumu daha yakından okumalısınız, @antony, özellikle gülen yüz ve yardım etmeye çalışanlar için çok değerli olmamalısınız. Sadece iki yöntemden kaçınmanız gerektiğine dair herhangi bir gerekçe vermediğinizi söylüyordum. Ve bu yardımcı bir fonksiyon kullanarak gerçek bir cevap, bu yüzden bir yorumda değil.
paxdiablo

1
+1: OP'nin kodu karıştırmama arzusu göz önüne alındığında, bu kabul edilmiş olandan çok daha iyi bir yaklaşımdır. (ya da daha önce davranır olarak istenen bir fonksiyonu olan bir kütüphane de dahil olmak üzere Nickkk çözümünü bkz.)
ToolmakerSteve

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

nDeğişken ise korkunç (bu nedenle biçim dizesini oluşturmanız gerekir), ancak bir sabit ise oldukça açıktır:

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

docs


İlginç bir alternatif, dört yıl önce verilen daha geleneksel yaklaşımlar göz önüne alındığında, bunu hiç kullanamadığımı hayal edemiyorum.
ToolmakerSteve

En iyi yanıt, Dize girişinin yalnızca bir kez okunduğundan, bir değişkende saklanmasına gerek yoktur, bu da düzgün bir şekilde gömülmesini mümkün kılar.
Profiterol

3

Alt dize yöntemini aşağıdaki gibi kullanın:

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

N dizenin uzunluğundan büyükse, bir yorumcunun işaret ettiği gibi bu bir istisna atar. Tek bir basit çözüm durumda tüm bu sarılmasıdır if(s.length()<n)sizin de elsefıkra, az önce / yazdırmak bütün Dize iade veya başka bir şekilde ele almak istediğinizi seçebilirsiniz.


1
Bu bir IndexOutOfBoundsException alma riski
antony.trupe

Bu arada, Java'da programlama yapmayı planlıyorsanız, String için API yöntemlerinin çoğunu ezberlemeye çalışmalısınız ( java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html ).
Matt Boehm

Zaten olarak, en azından kendisi tarafından, alt dize eledik değil cevap.
antony.trupe

Boyutu kontrol etmeniz veya istisnayı yakalamanız gerekir. Bunlardan birini yapmanın durumunuzda neden işe yaramayacağını sorabilir miyim?
Matt Boehm

3
Bu sorunun cevabı nasıl? Soru, önce nasıl bir boyut kontrolü yapmak zorunda kalmayacağınızı veya yakalanması gereken bir istisnaya neden olmamasını soruyordu.
ToolmakerSteve

3

Kotlin ile gelişecek kadar şanslıysanız , hedefinize ulaşmak için
kullanabilirsiniz take.

val someString = "hello"

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

0

ApacheCommons beni şaşırttı, StringUtils.abbreviate(String str, int maxWidth)"..." ifadesini ekleyerek postfix'i değiştirme seçeneği yok. WordUtils.abbreviate(String str, int lower, int upper, String appendToEnd)bir sonraki boş alana bakar.

Bunu burada bırakacağım:

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 Bu "ApacheCommons beni şaşırttı" cümlesinden dolayı. Kutsal ApacheCommons kütüphanesini eleştirerek günah işledim. Ya da her neyse ...
yuceel

0

Kotlin: (Birinin ihtiyacı varsa)

var mText = text.substring(0, text.length.coerceAtMost(20))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.