Prüfen, ob String eine nichtnegative ganze Zahl enthält

  • VB.NET

Es gibt 54 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Prüfen, ob String eine nichtnegative ganze Zahl enthält

    Hi,

    ich trau mich fast nicht diese Frage hier zu stellen. Sie könnte mit einem "na das ist doch vollkommen trivial" beantwortet werden. :)

    Aber ich komm halt nicht drauf. :(

    Ich habe eine TextFeld, nennen wird es TextBox1

    Dieses Feld kann jeden Schrott enthalten ... und ich möchte nun wissen, ob das eine (nicht-negative) ganze Zahl ist.

    Mir fallen da zwei Techniken ein:

    Zunächst mal lehne ich alle Leereingaben ab:

    VB.NET-Quellcode

    1. If TextBox1.Text.Trim = "" Then
    2. Label1.Text = "*** No Input"
    3. Exit Sub
    4. End If


    Und dann versuche ich einen Cint()

    VB.NET-Quellcode

    1. Try
    2. Dim myResult = CInt(TextBox1.Text.Trim)
    3. Label1.Text = "Result: " & myResult.ToString & "<<<"
    4. Catch ex As Exception
    5. MessageBox.Show("Button1: " & ex.Message)


    Das ist natürlich NICHT zielführend ... denn für die Eingabe 1,7 wird gerundet und man erhält 2. Allerdings wird für 1.002 die Zahl 1002 zurückgeliefert, was ja auch richtig ist.

    Die zweite Idee:

    VB.NET-Quellcode

    1. Dim myResult As Integer
    2. If Int32.TryParse(TextBox1.Text.Trim, myResult) Then
    3. Label1.Text = "Result: " & myResult.ToString & "<<<"
    4. Else
    5. MessageBox.Show("Button1: TryParse failed")
    6. End If


    Diese Lösung wird Komma Zahlen nicht zulassen. Und damit gibt es keine Rundungsfehler.

    Allerdings die Eingabe 1.002 führt zu einem Fehler, weil auch der Punkt abgewiesen wird.

    Beide Lösungen tun also nicht das was ich möchte.

    Man könnte IsNumeric verwenden:

    VB.NET-Quellcode

    1. If IsNumeric(TextBox1.Text.Trim) Then
    2. Label1.Text = "Result: is numeric"
    3. Else
    4. MessageBox.Show("Button3: Numeric failed")
    5. End If


    Da wird alles erkannt ... 1,7 .... 2.009 .... -20 .... etc.

    Aber ich muss dan halt noch anschließend prüfen ob es eine Ganzzahl ist .. also etwa mit int() abschneiden und dann auf Gleichheit prüfen ...

    Im Internet finde ich jede Menge Lösungsvorschläge ... aber so richtig überzeugt mich keine Lösung.

    Händisch könnte man das auch prüfen:

    Komma enthalten --> Eingabe ungülitig
    führendes + Zeichen 'entfernen
    Leerzeichen am Begin und Ende entrfernen (Trim)
    Alle Punkte entfernen
    Nullstring ---> Eingabe üngültig
    Prüfen ob nur Ziffern von 0 - 9 vorkommen --> Eingabe ungülitg
    ---> Eingabe gültig

    Das kann man machen ... es klingt für mich aber ziemlich umständlich. Zumal man ja streng genommen noch die decimal culture beachten müsste, also ob ein Dezimal Komma oder ein Dezimal Punkt verwednet wird !

    Gibt es denn für so eine Standard Anforderung keine bessere Lösung ?

    LG
    Peter



    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „Peter329“ ()

    Wenn du nur überprüfen willst, ob das eine nichtnegative Ganzzahl ohne irgendwas anderes drin ist (kein Whitespace davor oder danach und auch keine anderen Zeichen), kannst du einfach überprüfen, ob jedes Zeichen in deinem Feld eine Ziffer ist. Das sollte der einfachste Weg dafür sein.


    Edit:
    Okay, jetzt wo du deinen Eingangspost dermaßen editiert hast, ergibt meine Antwort natürlich keinen Sinn mehr. Bei dieser neuen Problemstellung hätte ich einfach Regex genommen und deine Beschreibung mit entsprechenden Regeln implementiert.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „nafets“ ()

    Um Deinen letzten eigenen Vorschlag zusammenzufassen: Alle Punkte zu entfernen und dann nur noch auf Ziffern zu prüfen, ist zwar gut, reicht aber auch nicht. Denn 122.252.31.211 ist eher eine IP als eine Zahl.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VaporiZed schrieb:

    Um Deinen letzten eigenen Vorschlag zusammenzufassen: Alle Punkte zu entfernen und dann nur noch auf Ziffern zu prüfen, ist zwar gut, reicht aber auch nicht. Denn 122.252.31.211 ist eher eine IP als eine Zahl.


    Eben, das ist es ja ... wenn man das wirklich wasserdicht per Hand abwickeln will, muss man ordentlichen Aufwand treiben ! Deshalb frage ich ja, ob es dafür nicht inzwischen eine vernünftige Technik gibt.

    Meine Routine sieht jetzt folgendermaßen aus:

    VB.NET-Quellcode

    1. Private Function IsNonNegative(_Input As String, ByRef myInteger As Integer) As Boolean
    2. Dim myInput = _Input.Trim
    3. myInteger = 0
    4. If myInput = "" Then Return False '*** No Input
    5. If Not IsNumeric(myInput) Then Return False '*** Not numeric
    6. If myInput.Contains(",") Then Return False '*** Not a whole number
    7. myInput = myInput.Replace(".", "") 'Cint does not accept decimal dots
    8. myInteger = CInt(myInput) 'Convert to integer
    9. If myInteger < 0 Then Return False '*** Not non negative
    10. Return True 'Input is valid
    11. End Function


    Aber vollständig ist diese Routine noch lange nicht ! (180,200.00 ... 180,0 ... 168.192.0.1 ... etc. etc.)

    Na ... da scheint wohl noch eine Lücke im .Net Framework zu bestehen ...

    LG
    Peter
    Da gibts nicht wirklich ne Lücke im Framework - das kann halt einfach nicht alles abdecken, was irgendjemand ein Mal benötigt.
    Wie willst du jetzt eigentlich mit den Punkten umgehen? Sollen das Tausendertrennzeichen sein? Und wenn das der Fall ist, wäre 192.168.101.101 auch ne valide Zahl oder willst du wiederum spezifisch was gegen IP-Adressen machen, auch wenn die entsprechend mit Tausendertrennzeichen sind? Die bisherige Aufgabenstellung lässt sich auf jeden Fall relativ simpel mit nem Regex lösen: ^\s*\+?\d{,2}(\.\d{3})*\s*$

    Edit: Wie wärs eigentlich mit ​Integer.Parse()? Wenn du wirklich nur Tausendertrennzeichen willst, kann das das über die Option ​NumberStyles.AllowThousands
    Eine Lücke würde ich das nicht nennen. Denn Du willst ja eine TextBox auf sehr spezielle Weise nutzen. Dafür wurde ja eigentlich z.B. ein NumericUpDown entwickelt. Du hast also nur spezielle Anforderungen, die Du an ein sehr generelles Control hast.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Peter329 schrieb:

    Dieses Feld kann jeden Schrott enthalten ... und ich möchte nun wissen, ob das eine (nicht-negative) ganze Zahl ist.
    Dazu verwendet man UInt.TryParse - feddich.
    Allerdings ist tryParse kleinlich, wenn du WhiteSpaces in deim String hast gibt das auch false zurück.
    Und natürlich auch wenn ein . vorkommt.
    Aber nach der von dir formulierten Anforderung ist UInt.TryParse() zuständig - sonst nix.
    Wenn das nicht macht, was du willst, musst du nochmal genauer definieren, was du willst.

    ah - bei TryParse biste ja schon:
    Allerdings die Eingabe 1.002 führt zu einem Fehler, weil auch der Punkt abgewiesen wird.
    Nein, das führt zu keinem fehler, sondern es gibt False zurück.
    Eben weil 1.002 keine GanzZahl ist.

    Gibt es denn für so eine Standard Anforderung keine bessere Lösung ?
    Du machst Witze.
    Deine Anforderung ist doch alles annere als Standard - mir deucht, sie ist widersprüchlich (und da gibts dann garkeine Lösung für).

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Deckt nicht Double.TryParse
    und wenn das True auf ist größer gleich 0 alles was du brauchst ab?

    Ich kann in die Textbox 123.123.123.123,123123 eingeben und es wird ordentlich zu einem double geparst.

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim zahl As Double = -1
    3. If Double.TryParse(TextBox1.Text, zahl) Then
    4. If (zahl >= 0) Then
    5. MessageBox.Show($"{TextBox1.Text} wurde erfolgreich zu: {zahl.ToString()}")
    6. End If
    7. End If
    8. End Sub


    Oder übersehe ich jetzt was?
    Grüße , xChRoNiKx

    Nützliche Links:
    Visual Studio Empfohlene Einstellungen | Try-Catch heißes Eisen

    xChRoNiKx schrieb:

    Oder übersehe ich jetzt was?
    ?

    Die Antwort war doch schon da?

    nafets schrieb:

    Wenn du wirklich nur Tausendertrennzeichen willst, kann das das über die Option ​NumberStyles.AllowThousands
    Das Problem ist doch nur, dass im standard das TryParse nicht die Deutsche Culture verwendet und daher den Punkt als Nachkommatrennzeichen sieht. Mit ​new CultureInfo("DE-de") klappt auch 12.345 als UInt und 12,23 eben nicht.
    Jetzt verstehe ich, warum 1.003 beim TryParse nicht funktioniert hat. Man muss nur den richtigen NumberStyle und die richtige Culture setzen.Dann klappt das auch. :)

    IP Adressen werden allerdings immer noch als gültige Zahl erkannt ... aber damit muss man halt leben oder das selbst händisch per .Split("."c) abhandeln.

    Es gibt also eine Funktion, mit der ich die Prüfung auch mit Tausender Trennzeichen durchführen kann. Und genau darum ging es mir ja auch: dass ich keine "Turnerei" veranstalte, wenn es dafür schon fertige .Net Funktionen gibt. Meine Kritik, dass so etwas im .Net fehlt ziehe ich damit natürlich zurück ! :)

    Vielen Dank an die Ratgeber, Daumen hoch und Thema erledigt !

    LG
    Peter

    Peter329 schrieb:

    IP Adressen werden allerdings immer noch als gültige Zahl erkannt
    Der nimmt die IP-Trennungspunkte als Tausender-Separatoren, das würde genau dann fehlschlagen, wenn im letzten Part nicht 3 Zeichen stehen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    Zitat von Peter329: „IP Adressen werden allerdings immer noch als gültige Zahl erkannt“Der nimmt die IP-Trennungspunkte als Tausender-Separatoren, das würde genau dann fehlschlagen, wenn im letzten Part nicht 3 Zeichen stehen.


    Das kann ich nicht bestätigen.

    Klar, die Punkte werden als Tausender Trennzeichen interpretiert. Aber dass beginnend ab dem ersten Punkt immer DREI Ziffern folgen, das wird nicht geprüft.

    Bei mir wird mit der Eingabe 168.192.0.1 die Zahl 16819201 zurück geliefert ... und das würden die meisten Leute nicht so ganz akzeptieren. :)

    Aber wie gesagt, das macht den Kohl ja nicht fett ... mit vier Zeilen Code kann man das selbst abfangen ...

    LG
    Peter
    Also das mit dem AllowThousands allein sollte nochmal auf Sinnhaftigkeit geprüft werden, da 1.......1.11..1 ebenfalls damit ein gültiger Integer wäre :S
    Da muss definitiv noch mehr eingestellt werden.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @Peter329 Das ganze ist sehr merkwürdig.
    Du kannst unheimlich viel festlegen, das kriegst Du allein raus.
    Ich hab mal mit CultureInfo und einmal mit NumberFormatInfo gearbeitet (je in einem Button_Click).
    Alles von der vorgefundenen Kultur.
    Das Ergebnis ist absolut nicht befriedigend, überzeuge Dich selbst:
    Form mit Button, CheckBox und 4 Labels.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. Dim culture As System.Globalization.CultureInfo = System.Globalization.CultureInfo.InvariantCulture
    4. Dim number As System.Globalization.NumberFormatInfo = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat
    5. Dim txt1 = "2,3,4,5"
    6. Dim txt2 = "123.4.56.......7"
    7. If CheckBox1.Checked Then ' die Strings unter der Art der Konvertierung tauschen
    8. txt2 = "2,3,4,5"
    9. txt1 = "123.4.56.......7"
    10. End If
    11. Dim value As UInteger
    12. Label1.Text = txt1
    13. Label2.Text = "error"
    14. If UInteger.TryParse(txt1, Globalization.NumberStyles.AllowThousands, culture, value) Then
    15. Label2.Text = value.ToString
    16. End If
    17. Label3.Text = txt2
    18. Label4.Text = "error"
    19. If UInteger.TryParse(txt2, System.Globalization.NumberStyles.AllowThousands, number, value) Then
    20. Label4.Text = value.ToString()
    21. End If
    22. End Sub
    23. End Class
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()

    Zitat von RFG

    Das Ergebnis ist absolut nicht befriedigend


    ... da könnte .Net sicher einiges Besser machen ... aber prinzipiell kann ich schon damit leben. So ein paar Schnörkel prüfe ich halt selbst ... man muss ja nicht in Schönheit sterben ...

    Aber mal etwas anderes ... was mir an der bisherigen Lösung missfällt: man muss die gewünschte "culture" vorgeben ... es wäre natürlich besser, wenn man die aktuelle culture" verwenden könnte ...

    Hab ich gesucht aber bisher nix Richtiges gefunden ... was wohl vermutlich an meiner mangelnden Ausdauer liegt ... :)

    Um es abzukürzen: kann mir man jemand sagen, wie ich die "aktuelle culture" abfragen kann ?

    LG
    Peter
    Entweder mit CurrentThread.CurrentCulture oder eben gar nix: If UInteger.TryParse(txt2, value) Then.
    Ich bemerke gerade meinen Irrtum in Post #16, InvariantCulture ist ja englisch.
    Wenn ich da deutsch nehme, ist wieder alles in Butter:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. Dim culture As System.Globalization.CultureInfo = New Globalization.CultureInfo("DE-de") 'System.Globalization.CultureInfo.InvariantCulture
    4. Dim number As System.Globalization.NumberFormatInfo = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat
    5. Dim txt1 = "2,3,4,5"
    6. Dim txt2 = "123.4.56.......7"
    7. If CheckBox1.Checked Then ' die Strings unter der Art der Konvertierung tauschen
    8. txt2 = "2,3,4,5"
    9. txt1 = "123.4.56.......7"
    10. End If
    11. Dim value As UInteger
    12. Label1.Text = txt1
    13. Label2.Text = "error"
    14. If UInteger.TryParse(txt1, Globalization.NumberStyles.AllowThousands, culture, value) Then
    15. Label2.Text = value.ToString
    16. End If
    17. Label3.Text = txt2
    18. Label4.Text = "error"
    19. If UInteger.TryParse(txt2, System.Globalization.NumberStyles.AllowThousands, number, value) Then
    20. Label4.Text = value.ToString()
    21. End If
    22. End Sub
    23. End Class

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Als Alternative zu UInteger.TryParse():

    VB.NET-Quellcode

    1. Dim x As Integer = 0
    2. Dim y As Double = 0
    3. If Integer.TryParse(TextBox1.Text, x) AndAlso ' Prüfung ob Textfeld eine Zahl enthält
    4. Double.TryParse(TextBox1.Text, y) Andalso
    5. y Mod x = 0 Andalso ' Prüfung ob Zahl eine Ganzzahl ist
    6. x >= 0 Then ' Prüfung ob Zahl positiv oder 0 ist
    7. Return True
    8. Else
    9. Return False
    10. End If


    Edit: Aufgrund des untenstehenden Kommentars von @VaporiZed


    Ein Computer wird das tun, was du programmierst - nicht das, was du willst.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Yanbel“ ()

    Z#5 ist etwas daneben gegangen. Aber was hat es mit dem y überhaupt auf sich?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.