Wie erhalte ich die ersten n Zeichen einer Zeichenfolge, ohne die Größe zu überprüfen oder Grenzen zu überschreiten?

162

Wie komme ich nin Java zu den ersten Zeichen eines Strings, ohne vorher eine Größenprüfung durchzuführen (Inline ist akzeptabel) oder ein Risiko einzugehen IndexOutOfBoundsException?

antony.trupe
quelle
1
Sofern Sie die Ausnahme nicht abfangen, weiß ich nicht, wie Sie den Fall behandeln möchten, in dem die Zeichenlänge größer als die Zeichenfolgenlänge ist.
Matt Boehm
2
Warum? Was ist Ihre Abneigung gegen das Überprüfen der Länge oder das Abfangen einer Ausnahme?
Paxdiablo
1
Aus Neugier, warum möchten Sie die Größenprüfung vermeiden? Dies ist nicht C.
Tom Hawtin - Tackline
Was ich ausdrücken wollte, war der Wunsch, einen if / else-Block zu vermeiden, keine Abneigung gegen die tatsächliche Überprüfung der Länge.
antony.trupe
Mögliches Duplikat von: stackoverflow.com/questions/8499698/…
Mulki

Antworten:

346

Hier ist eine gute Lösung:

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

Meinung: Diese Lösung ist zwar "ordentlich", aber meiner Meinung nach weniger lesbar als eine Lösung, die if/ elseauf offensichtliche Weise verwendet. Wenn der Leser diesen Trick nicht gesehen hat, muss er genauer nachdenken , um den Code zu verstehen. IMO, die Bedeutung des Codes ist in der if/ elseVersion offensichtlicher . Eine sauberere / besser lesbare Lösung finden Sie in der Antwort von @ paxdiablo.

Stephen C.
quelle
1
+1. Noch besser, wenn dies in eine Funktion namens safe_substring oder substring_safe eingeschlossen ist, wie die Antwort von paxdiablo, damit die Verwendung leichter zu lesen / zu erkennen ist.
ToolmakerSteve
Ich bin nicht einverstanden mit dem, was Sie sagen. Wenn dies in eine Funktion eingeschlossen ist, spielt es keine Rolle, was sich in der Funktion befindet , und jede "Ordentlichkeit" wird definitiv durch mangelnde Klarheit überwogen. Der Punkt dieser Lösung ist, dass sie für den Fall, dass Sie keine Wrapper-Funktion erstellen möchten, "ordentlich" ist .
Stephen C
88

Das Rad nicht neu erfinden ...:

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

Javadoc sagt:

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"

So:

StringUtils.substring("abc", 0, 4) = "abc"
Nickkk
quelle
1
Es beantwortet die Frage nicht, bietet aber trotzdem die Lösung. Wenn das OP verstehen kann, denke ich, dass dies eine bessere Lösung ist.
Aullah
5
Es kann auch nützlich sein, darauf hinzuweisen, dass dies StringUtils.substring(yourString, 0, n)nicht dasselbe ist wie yourString.substring(0, n). Ersteres stammt von StringUtils, während Letzteres verwendet String.substring(was eine Ausnahme darstellt, wenn der Endindex die Zeichenfolgenlänge überschreitet).
ToolmakerSteve
Genau wie zu Ihrer Information, wenn Sie in der Quelle nach dieser Methode suchen, behandelt sie den Fall, in dem das Ende größer als die Länge ist, indem Sie das Ende auf die Länge if (end > str.length()) { end = str.length();}
ändern
1
Der letzte Parameter von StringUtils.substring(String s, int start, int len)ist nicht len, sondern der Endindex.
Gorootde
StringUtils.substring ("abc", 0, 4) = "abc", hat bei mir funktioniert. Vielen Dank !
Akash5288
42

Apache Commons Lang hat hierfür eine StringUtils.leftMethode.

String upToNCharacters = StringUtils.left(s, n);
Skuli
quelle
Sollte dies nicht die beste Lösung sein? Warum stimmen nicht viele darüber ab?
Do Will
3
Vielleicht, weil andere Leute nicht die gleiche Meinung haben wie Sie? :-)
Stephen C
Diese Antwort kam viel später als das ursprüngliche Fragendatum.
Mulki
@DoWill: Da sich das Hinzufügen einer (anderen) Drittanbieter-Bibliothek zu Ihrer ausführbaren Umgebung nicht immer lohnt.
LarsH
12

Es gibt eine Klasse von Fragen zu SO, die manchmal weniger als vollkommen sinnvoll sind. Diese Frage ist gefährlich nahe :-)

Vielleicht könnten Sie Ihre Abneigung gegen eine der beiden Methoden erklären, die Sie ausgeschlossen haben.

Wenn es nur darum geht, dass Sie Ihren Code nicht mit ifAnweisungen oder Code zum Ausfangen von Ausnahmen überhäufen möchten , besteht eine Lösung darin, eine Hilfsfunktion zu verwenden, die sich um Sie kümmert, etwa:

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

Dadurch werden die Längen im Voraus überprüft und entsprechend gehandelt (entweder kleinere Zeichenfolge oder Pad mit Leerzeichen zurückgeben).

Dann müssen Sie sich in Ihrem Code überhaupt keine Sorgen mehr machen. Rufen Sie einfach an:

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

anstatt:

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

Dies würde in dem Fall funktionieren, in dem Sie sich Sorgen zu machen scheinen (basierend auf Ihren Kommentaren zu anderen Antworten) und den Code-Fluss nicht unterbrechen, wenn Sie viele Zeichenfolgen erstellen.

paxdiablo
quelle
1
Sie sollten den Kommentar genauer lesen, @antony, insbesondere den Smiley, und nicht so wertvoll gegenüber denen sein, die versuchen zu helfen. Ich habe nur gesagt, dass Sie keine Begründung dafür gegeben haben, warum Sie die beiden Methoden vermeiden mussten. Und dies ist eine echte Antwort, die eine Hilfsfunktion verwendet, weshalb sie nicht in einem Kommentar enthalten ist.
Paxdiablo
1
+1: Dies ist ein VIEL besserer Ansatz als der akzeptierte, da OP den Code nicht überladen möchte. (oder siehe Nickkks Lösung, eine Bibliothek einzuschließen, die bereits eine Funktion hat, die sich wie gewünscht verhält.)
ToolmakerSteve
12
String upToNCharacters = String.format("%."+ n +"s", str);

Schrecklich, wenn nes sich um eine Variable handelt (Sie müssen also die Formatzeichenfolge erstellen), aber ziemlich klar, wenn eine Konstante:

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

docs

13ren
quelle
Interessante Alternative, obwohl ich mir angesichts der traditionelleren Ansätze, die vor vier Jahren gegeben wurden, nicht vorstellen kann, sie jemals zu verwenden.
ToolmakerSteve
Beste Antwort, da die Eingabezeichenfolge nur einmal gelesen wird, sodass sie nicht in einer Variablen gespeichert werden muss, sodass sie sauber eingebettet werden kann.
Profiterole
3

Verwenden Sie die Teilzeichenfolgenmethode wie folgt:

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

Wenn n größer als die Länge der Zeichenfolge ist, wird eine Ausnahme ausgelöst, wie ein Kommentator hervorgehoben hat. Eine einfache Lösung besteht darin, all dies in die Bedingung if(s.length()<n)in Ihrer elseKlausel einzuschließen. Sie können wählen, ob Sie nur den gesamten String drucken / zurückgeben oder auf andere Weise behandeln möchten.

Matt Boehm
quelle
1
Dies riskiert eine IndexOutOfBoundsException
antony.trupe
Wenn Sie in Java programmieren möchten , sollten Sie übrigens versuchen, sich die meisten API-Methoden für String zu merken ( java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html ).
Matt Boehm
Ich habe Teilzeichenfolgen zumindest von sich aus bereits ausgeschlossen, da dies nicht die Antwort ist.
antony.trupe
Sie müssen entweder die Größe überprüfen oder die Ausnahme abfangen. Darf ich fragen, warum dies in Ihrer Situation nicht funktioniert?
Matt Boehm
3
Wie ist das eine Antwort auf die Frage? Die Frage war, wie man NICHT zuerst eine Größenprüfung durchführen oder eine Ausnahme verursachen muss, die abgefangen werden muss.
ToolmakerSteve
3

Wenn Sie das Glück haben, sich mit Kotlin zu entwickeln, können
Sie damit takeIhr Ziel erreichen.

val someString = "hello"

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

ApacheCommons hat mich überrascht, StringUtils.abbreviate(String str, int maxWidth)fügt "..." hinzu, es gibt keine Möglichkeit, Postfix zu ändern. WordUtils.abbreviate(String str, int lower, int upper, String appendToEnd)schaut zum nächsten leeren Raum auf.

Ich werde das hier einfach lassen:

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
quelle
1
@ VolkanGüven Es liegt an diesem Satz "ApacheCommons hat mich überrascht". Ich habe Sünde begangen, indem ich die heilige ApacheCommons-Bibliothek kritisiert habe. Oder was auch immer ...
Yuceel
0

Kotlin: (Wenn jemand braucht)

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