Controleer of een tekenreeks numeriek is in Java

1. Inleiding

Vaak tijdens het opereren op Draads, moeten we uitzoeken of a Draad is een geldig nummer of niet.

In deze zelfstudie onderzoeken we meerdere manieren om te detecteren of het gegeven is Draad is numeriek, eerst door gewoon Java te gebruiken, vervolgens door reguliere expressies en ten slotte door externe bibliotheken te gebruiken.

Zodra we de verschillende implementaties hebben besproken, gebruiken we benchmarks om een ​​idee te krijgen van welke methoden optimaal zijn.

2. Vereisten

Laten we beginnen met enkele voorwaarden voordat we verder gaan met de hoofdinhoud.

In het laatste deel van dit artikel zullen we de externe Apache Commons-bibliotheek gebruiken waarvoor we de afhankelijkheid ervan zullen toevoegen aan onze pom.xml:

 org.apache.commons commons-lang3 3.9 

De nieuwste versie van deze bibliotheek is te vinden op Maven Central.

3. Gebruik gewoon Java

Misschien wel de gemakkelijkste en meest betrouwbare manier om te controleren of een Draad is numeriek of niet is door het te ontleden met behulp van de ingebouwde methoden van Java:

  1. Integer.parseInt (tekenreeks)
  2. Float.parseFloat (tekenreeks)
  3. Double.parseDouble (tekenreeks)
  4. Long.parseLong (tekenreeks)
  5. nieuwe BigInteger (String)

Als deze methoden geen NumberFormatException, dan betekent dit dat het parseren is gelukt en het Draad is numeriek:

openbare statische boolean isNumeric (String strNum) {if (strNum == null) {return false; } probeer {double d = Double.parseDouble (strNum); } catch (NumberFormatException nfe) {return false; } retourneren waar; }

Laten we deze methode in actie zien:

assertThat (isNumeric ("22")). isTrue (); assertThat (isNumeric ("5.05")). isTrue (); assertThat (isNumeric ("- 200")). isTrue (); assertThat (isNumeric ("10.0d")). isTrue (); assertThat (isNumeric ("22")). isTrue (); assertThat (isNumeric (null)). isFalse (); assertThat (isNumeric ("")). isFalse (); assertThat (isNumeric ("abc")). isFalse ();

In onze isNumeriek () methode controleren we alleen op waarden die van het type zijn Dubbele, maar deze methode kan ook worden aangepast om te controleren op Geheel getal, Vlotter, Lang en grote aantallen door een van de ontleedmethoden te gebruiken die we eerder hebben ingeschakeld.

Deze methoden worden ook besproken in het artikel Java String Conversions.

4. Reguliere expressies gebruiken

Laten we nu regex gebruiken -? \ d + (\. \ d +)? om numeriek te matchen Snaren bestaande uit het positieve of negatieve gehele getal en drijvers.

Maar het spreekt voor zich dat we deze regex zeker kunnen wijzigen om een ​​breed scala aan regels te identificeren en af ​​te handelen. Hier houden we het simpel.

Laten we deze regex opsplitsen en kijken hoe het werkt:

  • -? - dit deel geeft aan of het opgegeven getal negatief is, het streepje “"Zoekt letterlijk naar het streepje en het vraagteken"?”Markeert zijn aanwezigheid als een optionele
  • \ d + - dit zoekt naar een of meer cijfers
  • (\. \ d +)? - dit deel van regex is om float-getallen te identificeren. Hier zoeken we naar een of meer cijfers gevolgd door een punt. Het vraagteken geeft uiteindelijk aan dat deze complete groep optioneel is

Reguliere uitdrukkingen zijn een zeer breed onderwerp. Bekijk onze tutorial over de Java Regular Expressions API voor een kort overzicht.

Laten we voorlopig een methode maken met behulp van de bovenstaande reguliere expressie:

privé Pattern patroon = Pattern.compile ("-? \ d + (\. \ d +)?"); openbare boolean isNumeric (String strNum) {if (strNum == null) {return false; } return pattern.matcher (strNum) .matches (); }

Laten we nu eens kijken naar enkele beweringen voor de bovenstaande methode:

assertThat (isNumeric ("22")). isTrue (); assertThat (isNumeric ("5.05")). isTrue (); assertThat (isNumeric ("- 200")). isTrue (); assertThat (isNumeric (null)). isFalse (); assertThat (isNumeric ("abc")). isFalse ();

5. Apache Commons gebruiken

In deze sectie bespreken we verschillende methoden die beschikbaar zijn in de Apache Commons-bibliotheek.

5.1. NumberUtils.isCreatable (tekenreeks)

NumberUtils van Apache Commons biedt een statische methode NumberUtils.isCreatable (tekenreeks) die controleert of a Draad is een geldig Java-nummer of niet.

Deze methode accepteert:

  1. Hexadecimale getallen die beginnen met 0x of 0X
  2. Octale nummers die beginnen met een 0
  3. Wetenschappelijke notatie (bijvoorbeeld 1.05e-10)
  4. Getallen gemarkeerd met een typekwalificatie (bijvoorbeeld 1L of 2.2d)

Als de meegeleverde string is nul of leeg / leeg, dan wordt het niet als een getal beschouwd en keert de methode terug false.

Laten we een aantal tests uitvoeren met behulp van deze methode:

assertThat (NumberUtils.isCreatable ("22")). isTrue (); assertThat (NumberUtils.isCreatable ("5.05")). isTrue (); assertThat (NumberUtils.isCreatable ("- 200")). isTrue (); assertThat (NumberUtils.isCreatable ("10.0d")). isTrue (); assertThat (NumberUtils.isCreatable ("1000L")). isTrue (); assertThat (NumberUtils.isCreatable ("0xFF")). isTrue (); assertThat (NumberUtils.isCreatable ("07")). isTrue (); assertThat (NumberUtils.isCreatable ("2.99e + 8")). isTrue (); assertThat (NumberUtils.isCreatable (null)). isFalse (); assertThat (NumberUtils.isCreatable ("")). isFalse (); assertThat (NumberUtils.isCreatable ("abc")). isFalse (); assertThat (NumberUtils.isCreatable ("22")). isFalse (); assertThat (NumberUtils.isCreatable ("09")). isFalse ();

Merk op hoe we het krijgen waar beweringen voor hexadecimale getallen, octale getallen en wetenschappelijke notaties in respectievelijk regel 6, 7 en 8.

Ook op regel 14, de string “09” geeft terug false omdat de voorgaande “0” geeft aan dat dit een octaal getal is en “09” is geen geldig octaal getal.

Voor elke input die terugkeert waar met deze methode kunnen we gebruiken NumberUtils.createNumber (tekenreeks) wat ons het geldige nummer zal geven.

5.2. NumberUtils.isParsable (tekenreeks)

De NumberUtils.isParsable (tekenreeks) methode controleert of het gegeven Draad is parseerbaar of niet.

Parseerbare getallen zijn getallen die met succes worden geparseerd door elke parse-methode zoals Integer.parseInt (tekenreeks), Long.parseLong (tekenreeks), Float.parseFloat (tekenreeks) of Double.parseDouble (tekenreeks).

in tegenstelling tot NumberUtils.isCreatable (), deze methode accepteert geen hexadecimale getallen, wetenschappelijke notaties of strings die eindigen op een typekwalificatie, dat wil zeggen, ‘F ',‘ F', ‘d ',' D ',' l 'of‘L '.

Laten we eens kijken naar enkele bevestigingen:

assertThat (NumberUtils.isParsable ("22")). isTrue (); assertThat (NumberUtils.isParsable ("- 23")). isTrue (); assertThat (NumberUtils.isParsable ("2.2")). isTrue (); assertThat (NumberUtils.isParsable ("09")). isTrue (); assertThat (NumberUtils.isParsable (null)). isFalse (); assertThat (NumberUtils.isParsable ("")). isFalse (); assertThat (NumberUtils.isParsable ("6.2f")). isFalse (); assertThat (NumberUtils.isParsable ("9.8d")). isFalse (); assertThat (NumberUtils.isParsable ("22L")). isFalse (); assertThat (NumberUtils.isParsable ("0xFF")). isFalse (); assertThat (NumberUtils.isParsable ("2.99e + 8")). isFalse ();

Op regel 4, in tegenstelling tot NumberUtils.isCreatable (), het nummer dat begint met een string “0” wordt niet beschouwd als een octaal getal, maar als een normaal decimaal getal en geeft daarom true terug.

We kunnen deze methode gebruiken als vervanging voor wat we hebben gedaan in sectie 3, waar we proberen een getal te ontleden en te controleren op een fout.

5.3. StringUtils.isNumeric (CharSequence)

De methode StringUtils.isNumeric (CharSequence) controleert strikt op Unicode-cijfers. Dit betekent:

  1. Alle cijfers van elke taal die een Unicode-cijfer is, zijn acceptabel
  2. Aangezien een decimaalteken niet wordt beschouwd als een Unicode-cijfer, is het niet geldig
  3. Voorlopende tekens (positief of negatief) zijn ook niet acceptabel

Laten we deze methode nu in actie zien:

assertThat (StringUtils.isNumeric ("123")). isTrue (); assertThat (StringUtils.isNumeric ("١٢٣")). isTrue (); assertThat (StringUtils.isNumeric ("१२३")). isTrue (); assertThat (StringUtils.isNumeric (null)). isFalse (); assertThat (StringUtils.isNumeric ("")). isFalse (); assertThat (StringUtils.isNumeric ("")). isFalse (); assertThat (StringUtils.isNumeric ("12 3")). isFalse (); assertThat (StringUtils.isNumeric ("ab2c")). isFalse (); assertThat (StringUtils.isNumeric ("12.3")). isFalse (); assertThat (StringUtils.isNumeric ("- 123")). isFalse ();

Merk op dat de invoerparameters in regel 2 en 3 getallen vertegenwoordigen 123 respectievelijk in het Arabisch en Devanagari. Omdat het geldige Unicode-cijfers zijn, retourneert deze methode waar op hen.

5.4. StringUtils.isNumericSpace (CharSequence)

De StringUtils.isNumericSpace (CharSequence) controleert strikt op Unicode-cijfers en / of spatie. Dit is hetzelfde als StringUtils.isNumeric () met het enige verschil dat het ook spaties accepteert, niet alleen voorloop- en volgspaties, maar ook als ze tussen getallen staan:

assertThat (StringUtils.isNumericSpace ("123")). isTrue (); assertThat (StringUtils.isNumericSpace ("١٢٣")). isTrue (); assertThat (StringUtils.isNumericSpace ("")). isTrue (); assertThat (StringUtils.isNumericSpace ("")). isTrue (); assertThat (StringUtils.isNumericSpace ("12 3")). isTrue (); assertThat (StringUtils.isNumericSpace (null)). isFalse (); assertThat (StringUtils.isNumericSpace ("ab2c")). isFalse (); assertThat (StringUtils.isNumericSpace ("12.3")). isFalse (); assertThat (StringUtils.isNumericSpace ("- 123")). isFalse ();

6. Benchmarks

Voordat we dit artikel afronden, gaan we enkele benchmarkresultaten doornemen om ons te helpen analyseren welke van de bovengenoemde methoden het beste zijn voor ons gebruik.

6.1. Eenvoudige benchmark

Ten eerste kiezen we voor een eenvoudige aanpak. We kiezen één tekenreekswaarde - voor onze test gebruiken we Geheel getal.MAX_VALUE. Vervolgens wordt die waarde getoetst aan al onze implementaties:

Benchmarkmodus Cnt Score Fouteenheden Benchmarking.usingCoreJava avgt 20 57.241 ± 0.792 ns / op Benchmarking.usingNumberUtils_isCreatable gemiddelde 20 26.711 ± 1.110 ns / op Benchmarking.usingNumberUtils_isParsable gemiddelde 20 46.577 ± 0.792 ns / op Benchmarking. Benchmarking.usingStringUtils_isNumeric gemiddelde 20 35.885 ± 1.691 ns / op Benchmarking.usingStringUtils_isNumericSpace gemiddelde 20 31.979 ± 1.393 ns / op

Zoals we zien, zijn de meest kostbare bewerkingen reguliere expressies. Daarna is onze kern op Java gebaseerde oplossing.

Merk bovendien op dat de bewerkingen die de Apache Commons-bibliotheek gebruiken in grote lijnen hetzelfde zijn.

6.2. Verbeterde benchmark

Laten we een meer diverse reeks tests gebruiken voor een meer representatieve benchmark:

  • 95 waarden zijn numeriek (0-94 en Geheel getal.MAX_VALUE)
  • 3 bevatten cijfers maar zijn nog steeds niet correct opgemaakt - ‘x0‘, ‘0..005′, en ‘–11
  • 1 bevat alleen tekst
  • 1 is een nul

Bij het uitvoeren van dezelfde tests, zien we de resultaten:

Benchmark-modus Cnt Score Error Units Benchmarking.usingCoreJava gem. 20 10162.872 ± 798.387 ns / op Benchmarking.usingNumberUtils_isCreatable gem. 20 1703.243 ± 108.244 ns / op Benchmarking.usingNumberUtils_isParsable gem. Benchmarking.usingStringUtils_isNumeric gemiddelde 20 1071.753 ± 8.657 ns / op Benchmarking.usingStringUtils_isNumericSpace gemiddelde 20 1157.722 ± 24.139 ns / op

Het belangrijkste verschil is dat twee van onze tests - de oplossing voor reguliere expressies en de op Java gebaseerde kernoplossing - van plaats zijn gewisseld.

Uit dit resultaat leren we dat het gooien en hanteren van de NumberFormatException, wat in slechts 5% van de gevallen voorkomt, heeft een relatief grote impact op de algehele prestatie. We concluderen dus dat de optimale oplossing afhangt van onze verwachte input.

We kunnen ook veilig concluderen dat we de methoden uit de Commons-bibliotheek moeten gebruiken of een methode die op dezelfde manier is geïmplementeerd voor optimale prestaties.

7. Conclusie

In dit artikel hebben we verschillende manieren onderzocht om te achterhalen of a Draad is numeriek of niet. We hebben naar beide oplossingen gekeken: ingebouwde methoden en ook externe bibliotheken.

Zoals altijd is de implementatie van alle bovenstaande voorbeelden en codefragmenten, inclusief de code die wordt gebruikt om benchmarks uit te voeren, te vinden op GitHub.


$config[zx-auto] not found$config[zx-overlay] not found