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.

    Neu

    VaporiZed schrieb:

    Aber was hat es mit dem y überhaupt auf sich?


    Eigentlich nur um Nachkommastellen auszuschließen. Sind Integerwert und Doublewert gleich handelt es sich um eine Ganzzahl oder wie oben beschrieben: Bleibt bei der Division des Doublewerts durch den Integerwert kein Rest, sind die Zahlen identisch.


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

    Neu

    ErfinderDesRades schrieb:

    Hier sind jetzt so einige "Lösungen" vorgestellt worden, andere nicht, und mich würd jetzt malwieder interessieren,
    1. wie nun die letztendliche Aufgabenstellung lautet
    2. wie Peter329s letztendliche Lösung dazu aussieht


    Die Aufgabenstellung ist doch ganz einfach:

    Ein Textfeld wird mit .ToString("n0") befüllt. Damit wird eine GanzZahl mit Tausender Trennzeichen angezeigt.

    Der Anwender kann diese Zahl beliebig abändern. Ich möchte prüfen, ob die Eingabe korrekt ist. Alle Eingaben, die "normale" Menschen als "richtig" ansehen würden, sollen akzeptiert werden. Punkt und Komma, sollen gemäß der aktuellen "Culture" interpretiert werden.

    Gültig sind (mit deutscher Culture):

    2925
    217
    30.500.072
    18,0
    +320
    + 27

    Ungülitg sind

    1a7
    18,3
    -19
    ++30
    .200
    168.192.0.1
    240. 192.100.200

    Das ist mein Coding:

    VB.NET-Quellcode

    1. Public Function IsWholeNonNegative(s As String, ByRef x As Integer) As Boolean
    2. 'Initialize return value
    3. x = 0
    4. 'Check input is numeric
    5. If Not Int32.TryParse(s,
    6. NumberStyles.Any,
    7. Thread.CurrentThread.CurrentCulture,
    8. x) Then Return False
    9. 'Check input is a whole number
    10. Dim y As Double = 0
    11. If Not Double.TryParse(s, y) AndAlso y Mod x = 0 Then Return False
    12. 'Check input is non negative
    13. If Not x >= 0 Then Return False
    14. 'Check format (thousand separarators and + sign)
    15. Dim ss = s.Split(","c) 'Remove decimal comma
    16. Dim blk = ss(0).Split("."c) 'Get blocks of thousand
    17. Dim cnt = blk.Length 'Get number of blocks
    18. If cnt > 1 Then 'Thousand separators specified
    19. If blk(0).StartsWith("+") Then _
    20. blk(0) = blk(0).Substring(1).Trim 'Remove one leading + sign
    21. Dim l = blk(0).Length 'Check length first of block (1 - 3)
    22. If Not (1 <= l AndAlso l <= 3) Then Return False
    23. End If
    24. For i = 1 To cnt - 1 'Check length of subsequent blocks (3)
    25. If blk(i).Length <> 3 Then Return False
    26. Next
    27. 'Check completed
    28. Return True
    29. End Function


    Verbesserungsvorschläge sind willkommen. :)

    LG
    Peter

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

    Neu

    Wenn die Aufgabenstellung so einfach ist, wie du denkst, warum hast du das nicht bereits im Eröffnungspost schon reingeschrieben?
    Ich denke, dass die Antworten ganz anders ausgesehen hätten. Niemand hat sich die Frage gestellt, wie genau der Inhalt deiner Textbox zustande kommt.
    Die Information, dass es sich hierbei um eine aktive Erfassung von Werten handelt ist deswegen wesentlich, weil man hier bereits ansetzen könnte.
    Man kann einer Textbox durchaus sagen, dass sie auf das Textchange Ereignis reagieren soll (weil das auch reinkopierten Text erfasst, es gibt auch andere Ereignisse die hierfür geeignet wären) und einfach nur bestimmte Zeichen überhaupt erlauben soll. Das erleichtert das spätere Parsen ungemein.

    Mit anderen Worten, die erste Frage von @ErfinderDesRades im Post 21 ist die wichtigste Frage überhaupt, nur hat sie niemand gestellt. Und du gingst mal eben einfach so davon aus, dass es klar sei.

    Neu

    Boah, die Anforderungen sind aber doch größer als erwartet. + 27 soll akzeptiert werden, weil es eine Schreibweise ist,

    Peter329 schrieb:

    die "normale" Menschen als "richtig" ansehen würden
    ? Ok. Wäre für mich schon grenzwertig, da ein Vorzeichen ohne Lücke vor einer Zahl stehen muss.
    Was ist mit 10e12, 2^23?

    VB.NET-Quellcode

    1. If Not x >= 0 Then Return False
    -> If x < 0 Then Return False
    Aber ohne es ausgetestet zu haben: Ab Z#18 ist doch kein Weiterkommen. Die ganzen Textspielereien müssten doch vor der Zahlumwandlung hin. Ein + 23 würde es nie bis Z#18 schaffen.
    Das mit dem Double kapier ich immer noch nicht. Wenn ein Text nicht in einen Integer geparst werden kann (Z#7), dann bringt doch das Parsen in ein Double nix. Selbst wenn da rauskäme, dass der Text in ein Double konvertiert werden kann: Was nützt Dir dieses Wissen?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.

    Neu

    Erst mal Danke, dass ihr euch mit meinem Anliegen befasst habt.

    @Dksksm: das mit dem Abfangen von Eingaben ist halt eine Frage der "Usability" ... ich halte nichts davon, weil das fehlerträchtig ist ! Wenn der Anwender etwa 67k239 eingibt und ich das "k" z.B. per KeyPress unterdrücke, dann lautet die Eingabe 67239 ... und damit kann ein Fehler unentdeckt bleiben. Ich nehme User Eingaben immer so entgegen wie sie sind und verändere sie auch nicht im Program. Das erleichtert nicht zuletzt das Debugging.

    @VaporiZed: das mit der Abfrage "not x >=0" verwende ich ganz bewusst ! Ich schreibe immer die Bedingung, die ERFÜLLT sein soll ... und frage dann mit NOT ab, ob sie NICHT erfüllt ist. Das ist halt eine Konvention, die ich für sinnvoll halte - auch wenn man das anders sehen kann. Aber es ist besser eine einheitliche CodeTechnik zu verwenden als ständig den Stil zu wechseln.

    Tatsächlich hat @VaporiZed Recht ... die Sache mit dem "modulo" ist nicht notwendig, weil das schon vom Int32.TryParse abgefangen wird. Also raus damit. :)

    VaporiZed schrieb:


    Aber ohne es ausgetestet zu haben: Ab Z#18 ist doch kein Weiterkommen.


    Das solltest du aber testen. :)

    Die Eingabe 1.2.3 liefert nämlich 123 ... und das würden normal denkende Menschen nicht als richtig ansehen.

    Exponentielle Schreibweisen z.B. 2e5 oder Rechenausdrücke z.B. 2^8, würden normale Leute nicht verwenden. Blöderweise akzeptiert TryParse 2e5 ... das muss man also abfangen.

    So sieht meine Routine jetzt aus:

    VB.NET-Quellcode

    1. Public Function IsWholeNonNegative(str As String, ByRef x As Integer) As Boolean
    2. 'Initialize return value
    3. x = 0
    4. 'Check valid digits
    5. Dim s = str.Trim 'Remove leading and trailing spaces
    6. If s.StartsWith("+") Then s = s.Substring(1).Trim 'Remove + sign
    7. Dim ValDigits = "0123456789.,"
    8. For i = 0 To s.Length - 1
    9. If Not ValDigits.Contains(s(i)) Then Return False
    10. Next
    11. 'Check input is a whole number
    12. If Not Int32.TryParse(s,
    13. NumberStyles.Any,
    14. Thread.CurrentThread.CurrentCulture,
    15. x) Then Return False
    16. 'Check input is non negative
    17. If Not x >= 0 Then Return False
    18. 'Check format (thousand separarators and + sign)
    19. Dim blk = s.Split("."c) 'Get blocks of thousand
    20. Dim cnt = blk.Length 'Get number of blocks
    21. If cnt > 1 Then 'Thousand separators specified
    22. Dim l = blk(0).Length 'Check length first of block (1 - 3)
    23. If Not (1 <= l AndAlso l <= 3) Then Return False
    24. End If
    25. For i = 1 To cnt - 1 'Check length of subsequent blocks (3)
    26. If blk(i).Length <> 3 Then Return False
    27. Next
    28. 'Check completed
    29. Return True
    30. End Function



    Gibt es Verbesserungsvorschläge ?

    LG
    Peter

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

    Neu

    @Peter329 Wenn da in der TextBox noch editiert werden darf, dann lass doch einfach nur Tastendrücke zu, die zu einer UInteger-Zahl passen: 0...9 und Editier-Tasten und desgleichen bei C&P und feddich.
    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!

    Neu

    Peter329 schrieb:

    Das solltest du aber testen. Die Eingabe 1.2.3 liefert nämlich 123 ... und das würden normal denkende Menschen nicht als richtig ansehen
    Andersrum ist mein Problem: Du willst, dass + 23 durchkommt. Das scheiterte aber mit dem Integer.TryParse schon vorher. Mit dem jetzigen Code geht es. Weil Du einen Teil der Textbearbeitung vor das Parsen gestellt hast.
    Das mit der Not Sollbedingung ist Deine Codekonvention, ok, das war mir nicht klar. Daran will ich natürlich nicht rütteln.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.

    Neu

    :huh:
    Da wir den Anwendungsfall nicht kennen, aber seit Post#1 klar ist, dass eine positive Ganzzahl rauskommen soll, widerspreche ich dem Einwand. Kaufmännisch wird da sicher nix ablaufen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.

    Neu

    Kasi schrieb:


    aber in der Buchhaltung und in vielen anderen Bereichen müssen negative Zahlen erlaubt sein
    eigenartige Anforderung die du da hast


    nur spaßeshalber:

    auch in der Buchhaltung gibt es Felder, die nicht-negativ und ganzzahlig sein müssen ... z.B. in der Bestandsführung ,,, -2,7 Kraftfahrzeuge wird die Betriebsprüfung vermutlich nicht so ganz akzeptieren.

    In meinem Fall, enthält das Textfeld übrigens einen Zähler ... da ist meine Anforderung vielleicht nicht gar so eigenartig. :)

    Aber jetzt habe ich doch noch eine Frage:

    Zeile 24:

    VB.NET-Quellcode

    1. Dim blk = s.Split("."c) 'Get blocks of thousand


    Diese Anweisung ist natürlich nur richtig, wenn die Culture PUNKTE als Tausender Trennzeichen verwendet.

    Das ist in der "deutschen Culture" (die ich verwende) der Fall. Wie das in anderen Cultures aussieht weiß ich nicht. Und alle Cultures daraufhin überprüfen möchte ich (faul wie ich nun mal bin) auch nicht ! Zumal sich das ja auch irgendwann ändern könnte.

    Mit anderen Worten: Wie kann ich herausfinden, ob ein Punkt oder ein Komma als Tausender Trennzeichen verwendet wird ... ?

    Natürlich könnte ich Cint("1000").ToString("n0") verwenden, um das per Substring heraus zu kriegen. Aber das ist "schweinisch" ... und mir liegt doch sehr an anständigem Coding ... :)

    Weiß jemand wie ich das mit "regulären" Befehlen hin bekommen ?

    LG
    Peter

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

    Neu

    Peter329 schrieb:

    -2,7 Kraftfahrzeuge
    Da ließe sich auch ein NumericUpDown verwenden, maximale obere Grenze und feddich.
    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!

    Neu

    z.B.

    VB.NET-Quellcode

    1. Dim SeparatorVorUndNachDemKomma = Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator
    2. Dim TausenderSeparator = Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberGroupSeparator
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.

    Neu

    @RFG

    Na ja, ein NumericUpDown wäre schon eine Alternative. Da erhalte ich eine Ganzzahl aus einem definierten Intervall ...

    Wenn das Werte zwischen 0 und 10 betrifft ist das schon in Ordnung. Aber mein Zähler kann durchaus Wert von mehreren Millionen enthlalten. Ich weiß nicht, ob irgend jemand so einen NumericUpDown als "user friendly" bezeichnen würde. ich erwarte da ganz andere Stellungnahmen ... :)

    @VaporiZed

    Jip ... das war die Anweisung, die ich gesucht hatte.


    Damit bin ich völlig happy. Alles in allem wieder mal ein geradezu klassisches Beispiel dafür, wie die geballte Schwarmintelligenz eines Forums dazu in der Lage ist, ein recht komplexes Problem punktgenau zu lösen.

    DANKE !

    LG
    Peter

    LG
    Peter

    Neu

    Das NUD-Argument versteh ich nicht. Man muss die Pfeiltasten ja nicht nutzen. Man kann ja selber eintippen und Ober- und Untergrenze festlegen. Es geht ja nur darum, dass das NUD eben nur Zahlen in einem gewissen Bereich akzeptiert. Aber das hatte ich ja in Post#6 schon erwähnt.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.

    Neu

    Peter329 schrieb:

    Aber mein Zähler kann durchaus Wert von mehreren Millionen enthlalten.
    NumericUpDown.Value und NumericUpDown.Maximum sind vom Typ Decimal.
    Sieh Dir mal an, was da als Decimal.MaxValue möglich ist. ;)
    ====
    10000000000000000000000000000 funktioniert als NUD.MaxValue.
    Decimal.MaxValue = 79228162514264337593543950335 funktioniert auch.
    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“ ()

    Neu

    Und auf welchen Wert wirst du die Obergrenze festlegen ? Na gut, eben auf den Maximalwert eines Integer ... auch wenn das dann weit jenseits von "Gut und Böse" ist. :)

    Aber von mir aus ... dann ist ein NumericUpDown eben eine Alternative.

    Für meinen Geschmack ist das halt eher "user friendly", wenn ich den aktuellen Wert anzeige und den User OHNE up-and-down einen neuen Wert eintippen lasse - weil sich der Wert ohnehin üblciherweise gravierend vom angezeigten Wert unterscheiden wird. Aber das ist halt von den Besonderheiten der Anwendung abhängig und ansonsten Geschmackssache. Und über Geschmack lässt sich bekanntlich nicht streiten. :)

    Die prinzipielle Auigabe, einen String auf die Eigenschaft "IsWholeNonNegative" zu prüfen, halte ich inzwischen für ausdiskutiert. Es sei denn, jemand hätte da jetzt noch einen wesentlich neuen Gesichtspunkt einzubringen.

    LG
    Peter

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

    Neu

    @Peter329 Mach die Obergrenze hinreichend groß, 10 * Dein persönliches Maximum.
    Frag Frau Google nach vb.net numericupdown ohne spinbutton
    Sieh mal hier: NumericUpDown-Steuerelement ohne Drehfeld möglich?
    ich weiß aber nicht, obs gelöst wurde.
    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!