Position einer unbekannten 3-stelligen-Zahl in einem String finden

Groomit

Mitglied
Hallo,

ich sehe im Moment den Wald vor lauter Bäumen nicht.

Der Wert der 3-Stelligen Zahl kann einen beliebigen Wert annehmen.
Java:
        String s = "abcdef 255 jklö";
        Pattern p = Pattern.compile(".*\\d{3}.*");
        Matcher m = p.matcher(s);
        boolean b = m.matches();

Damit weiß ich lediglich, das eine 3-stellige-Zahl im String vorhanden ist, ich benötige aber auch die Position im String.

Hat jemand einen heißen Tipp?

Danke und Gruß
Groomit
 
Wobei da dann vermutlich die .* weg müssen, denn sonst fängt es immer an index 0 an fürchte ich.

Hast Recht, sollte man als Gruppe machen:

Java:
Pattern.compile(".*?(<NUMBER>\\d{3}).*?");
matcher.start("NUMBER");

Oder halt ohne die fuehrenden Punkte:

Java:
Pattern.compile("\\d{3}");
matcher.start();

Bin gerade auch nicht taufrisch, stelle ich fest...
 
@Groomit, wäre gut, wenn Du die richtige Antwort auch markieren würdest, dann sieht man gleich in der Übersicht, dass die Frage beantwortet ist und kann sich das Lesen des Threads sparen.
 
Valide 3-stellige Zahlen
Und damit hast Du hier schon deutlich mehr in die Aufgabe hinein interpretiert, als gegeben.

Der TE schien mit seinem Algorithmus / regulären Ausdruck ja schon soweit zufrieden. Es störte ihn nur eine Sache:
Damit weiß ich lediglich, das eine 3-stellige-Zahl im String vorhanden ist, ich benötige aber auch die Position im String.
Daher kann man auf diesem regulären Ausdruck ja weiter aufsetzen, wie es getan wurde. Wenn man sich damit nicht weiter auseinander setzen möchte, dann könnte man die Zahl in eine Group setzen und auslesen - dann wäre auch ein String.indexOf denkbar als mögliche Lösung (So man nicht zu viel mit regulären Ausdrücken machen möchte.)



Bezüglich der "validen 3-stelligen Zahlen": Dies kann sehr vieles sein:
- Auf Grund des Beispiels könnte man annehmen, dass da Whitespaces zur Abgrenzung vorhanden sind.
- Es könnte aber auch einfach sein, dass der String das Format hat XXXXXzzzXXXXXX mit jeweils beliebigen Mengen X, jedes einzelne X ist ein beliebiges Zeichen (incl. Ziffern!) und es werden alle möglichen zzz mit jedem z eine Ziffer gesucht. Dann würde bei aaa1234aa sowohl die 123 als auch die 234 gesucht werden - unabhängig davon dass 1234 eben eine vierstellige Zahl wäre.
- Selbst wenn man valide 3-stellige Zahlen sucht, dann wäre 0123 ggf. keine valide 3 stellige Zahl, da es eben 4-Stellig ist. Wenn man die 0er nicht zählt, dann wäre 012 übrigens auch keine valide 3-stellige Zahl, da diese nach den angegebenen Regeln nur einer 12 entsprechen würde.

Hintergrund ist halt, dass wir nicht wissen, was da in dem String ist. Hier ist also nicht vom rein mathematischen Ansatz auszugehen, das nur eine Zahl an sich betrachtet, die für sich klar begrenzt ist sondern hier gehen wir von einer beliebigen Zeichenkette aus und es ist eben nicht gesagt, die diese Grenzen aussehen und was man da alles begrenzen muss. Daher ist 1234 keine 3-stellige Zahl. Der String "1234" enthält aber durchaus 2 3-stellige Zahlen: 123 und 234.

Valide 3-stellige Zahlen via Regex zu ermitteln, ist nicht so einfach.
Wenn man die Regeln kennt, dann kann man das durchaus als RegeEx darstellen. Dann muss vor der Zahl der Anfang des Strings sein oder beliebige Zeichen, die keine Ziffern sind. Dann dürften beliebige Anzahl 0er folgen. Dann kämen die 3 Ziffern und danach entweder keine Ziffer oder das Ende des Strings. (Das dürfte ungefähr dem entsprechen, das Du gemacht hast)

Ansonsten sollte man bei so Codes immer darauf achten, dass dieser lesbar ist. Eine Methode mit mehreren verschachtelten Schleifen und einigen if und if/else würde ich nicht darunter verstehe. Hier wäre ein Refactoring also dringend notwendig so man verständlichen Code haben möchte.

Ansonsten gibt es einen ganz einfachen Ansatz ohne Reguläre Ausdrücke der das Problem in einfache Teilprobleme unterteilt:
a) Ich splitte den String so auf, dass ich nur Zeichenketten mit Ziffern habe (ein split("[^0-9]") könnte das schon machen)
b) jetzt könnte man beliebige Prüfungen anwenden, die man für richtig erachtet und die Werte beliebig auswerten. (führende 0er könnte man weglassen so es mehr als 3 Stellen sind, lange Ziffern könnte man in die 3er Substrings aufteilen, u.s.w.) Wir kennen halt die Regeln nicht aber wir haben die Bedingung recht schön eigenständig gemacht.
c) Am Ende hat man die Zielmenge der Teilstrings und kann dann die Stellen, an denen diese sich befinden, ermitteln (Mehrmaliger Aufruf von String.indexOf).

Das einfach einmal zu meiner Sicht auf diese Aufgabenstellung.
 
@Deface3 Versteh' mich jetzt nicht falsch, das ist recht schoener Code den du da geschrieben hast, aber das sind mit Abstand die schlechtesten Namen fuer Variablen die ich in letzter Zeit gesehen habe. "a" und "b" zum Beispiel sind komplett wertfrei. AUch wenn es kleine, schnelle Beispiele sind (oder vielleicht auch gerade dann) sollte man darauf achten brauchbare Variablennamen zu verwenden um das Beispiel klar zu gestalten.

Java:
import java.util.LinkedList;
import java.util.List;

public class Suchen {
    public static class MatchGroup {
        public String originalString;
        public int matchStartIndex;
        public int matchEndIndex;

        public MatchGroup(String originalString, int matchStartIndex, int matchEndIndex) {
            this.originalString = originalString;
            this.matchStartIndex = matchStartIndex;
            this.matchEndIndex = matchEndIndex;
        }

        public String substring() {
            return originalString.substring(matchStartIndex, matchEndIndex) + " (" + matchStartIndex + "," + matchEndIndexb + ")";
        }
    }

    public static List<MatchGroup> findeDreistelligeNummern(String string) {
        List<MatchGroup> groups = new LinkedList<>();
        for (int index = 0; index < string.length(); index++) {
            if (Character.isDigit(string.charAt(index))) {
                while (index < s.length() && string.charAt(index) == '0') {
                    index++;
                }
                if (index == string.length() || !Character.isDigit(string.charAt(index))) {
                    groups.add(new MatchGroup(string, index - 1, index));
                } else {
                    int endIndex = index + 1;
                    try {
                        while (endIndex < string.length() && Integer.parseInt(string.substring(index, endIndex)) < 1000) {
                            endIndex++;
                        }
                    } catch (NumberFormatException ignore) {
                    }
                    groups.add(new MatchGroup(s, index, endIndex - 1));
                    index = endIndex - 2;
                }
            }
        }
        return groups;
    }

    public static void main(String[] args) {
        findeDreistelligeNummern("00aj0sf001001hs000zfs1d2n34h678m9999f0")
                .stream()
                .map(MatchGroup::substring)
                .forEach(System.out::println);
    }
}

Auszerdem funktioniert das nicht richtig, es produziert bei mir folgende Ausgabe:

Code:
0 (1,2)
0 (4,5)
100 (9,12)
1 (12,13)
0 (17,18)
1 (21,22)
2 (23,24)
34 (25,27)
678 (28,31)
999 (32,35)
9 (35,36)
0 (37,38)

Desweiteren ist die Interpretation von "001001" fuer diese Aufgabe schwierig. Koennte jetzt "1" und "1" sein oder "100" und "1".
 
Hallo Tobias, schön, dass Du Dir wieder einen Account gemacht hast.

Generell kannst Du Deinen Code so schreiben wie Du willst. Wenn Du in einem Forum eine Antwort verfasst, dann ist es aber nun einmal so, dass:

a) Leute schauen ob dies z.B. die Anforderungen erfüllt.

b) Ggf. Code einem kurzen Review unterziehen. Und da gibt es dann konstruktive Kritik. Die kannst Du annehmen oder es auch sein lassen.

c) Leute sich überlegen, wie hilfreich so eine Antwort auch ist. Wie gross schätzt Du die Chance ein, dass der TE Deine Antwort als hilfreich erachtet? (Nein, dass will ich nicht diskutieren. Ich habe mir da meine Gedanken gemacht und habe da meine Sicht. Ich will das aber nicht diskutieren. Das ist eine reine Denkanregung.
 
nummer("00aj0sf001001hs000zfs1d2n34h678m9999f0").stream().map(MatchGroup::substring).forEach(System.out:😛rintln);
nur weil man streams benutzt ist der code nicht unbedingt gut möchte ich mal an einer stelle anmerken

c# hat das gleiche als LINQ und sollte mit bedacht eingesetzt werden da man einfachen code nur so sehr verkompliziert nur um ihn in einer zu haben
 
Welche Anforderungen? Die Konradschen Namenskonventionen? Spielst du wieder Alleinherrscher?
Das überrascht mich jetzt doch etwas, denn ich dachte eigentlich, dass es in diesem Punkt bereits einen Konsens gegeben hätte:
Jo, ich bin davon ausgegangen, dass er Zahlen zwischen 0 und 999 ohne führende Nullen sucht. Das war vielleicht etwas zu viel in die Aufgabe hineininterpretiert.

Und bezüglich Clean Code bin ich nur ein kleines Licht. Ich plappere einfach nur nach, was Andere so erzählen, z.B. Uncle Bob. Solltest Du Dir evtl. auch einmal an tun. Das Thema Clean Code ist für Software Entwickler nun einmal sehr wichtig. (Ok, Du hast in der Vergangenheit oft gesagt, dass Du das eben nicht bist. Aber dann stellt sich die Frage, was Dich in dem Themengebiet denn dann zum Spezialisten macht - Deiner Meinung nach?)

Aber das ist nicht das Thema. Meine Position habe ich deutlich gemacht und ich denke, dass diese so auch verständlich ist. Daher muss das nicht weiter vertieft werden.
 
Sorry, aber das Thema war schlicht und einfach eine Bewertung von Code. Und da geht es auch durchaus um Clean Code. Und Du hast sinnloses Zeug gebrabbelt von wegen "Die Konradschen Namenskonventionen? Spielst du wieder Alleinherrscher?"

Daher habe ich einfach nur gesagt, woher Dinge kommen, die ich so von mir gebe - und da geht es nun einmal nicht um Regeln, die von mir stammen.

Ganz einfache Logik, nicht schwer zu verstehen. Aber vielleicht will der kleine Tobias auch einfach nur aus dem Bällespieleparadies abgeholt werden?
 
angemessenheit an das wissen des TEs spielte da aber keine rolle?
Das Thema Clean Code umfasst sowas natürlich auch (aus meiner Sicht). Man muss sich immer überlegen, wer denn in der Lage sein soll, den Code zu lesen. Je nachdem können dann mehr oder weniger Mittel eingesetzt werden. Aber das tritt im Forum eher in den Hintergrund. In #12 habe ich das ja versucht, das etwas darzustellen und da wäre es der Punkt c).

Aber das will ich eigentlich nicht weiter vertiefen. Meine Sichtweise habe ich darstellen können und ich denke, dass da nicht viel mehr zu sagen ist. Das kann dann ansonsten jeder so sehen, wie er möchte.
 

Zurück
Oben