Expresie regulată pentru a se potrivi literal întreg

0

Problema

Mă gândeam la parsarea o listă de numere întregi (de la o proprietate string). Cu toate acestea, aș dori pentru a merge dincolo de doar pozitive și negative, valori zecimale și analiza orice șir de caractere care indică un Java întreg literal (JLS 17) pot fi găsite în codul sursă. În mod similar, aș vrea să fiu indulgent cu privire la orice prefixe, separatoare și anexe în jurul valorii de numere întregi ei înșiși. Cu alte cuvinte, vreau să-i găsească folosind apeluri repetate la Matcher.find().

Există o expresie regulată care se potrivește posibil Java întreg literale? Ea nu are nevoie pentru a verifica limitele superioare și inferioare.


Chiar dacă am făcut-o în mod explicit link-ul de la JLS, eu vă va arăta unele valide și nevalide de numere:

  • -1de : 1 este potrivit, dar minus este un operator unar (I să reglați dacă este necesar)
  • 0x00_00_00_0F: valoarea cincisprezece este potrivit ca de cifre hexazecimale, cu o subliniere pentru a separa cele două nibbles
  • 0b0000_1111: valoarea cincisprezece în binar este compensată
  • 017: octal valoarea de cincisprezece ani este compensată
integer java literals regex
2021-11-23 21:48:28
3

Cel mai bun răspuns

4

Ceva de genul asta:

zecimal:
(?:0|[1-9](?:_*[0-9])*)[lL]?

hexazecimal:
0x[a-fA-F0-9](?:_*[a-fA-F0-9])*[lL]?

octal:
0[0-7](?:_*[0-7])*[lL]?

binar:
0[bB][01](?:_*[01])*[lL]?

Toate împreună: (în freespacing modul)

(?:
    0
    (?:
        x [a-fA-F0-9] (?: _* [a-fA-F0-9] )*
      |
        [0-7] (?: _* [0-7] )*
      |
        [bB] [01] (?: _* [01] )*
    )?
  |
    [1-9] (?: _* [0-9] )*
)
[lL]?

testați-l

2021-11-23 22:47:19

Ah, da, asta mi-ar lua un drum lung. Nu-l permite multiple subliniază totuși? Poate că ? ar trebui să fie o *?
Maarten Bodewes

@MaartenBodewes: Cum am inteles de la doc, subliniaza nu ar trebui să fie contigous, dar poate am greșit? (cu alte cuvinte este 1____1 permis ?). Rețineți că grupul în interiorul căruia opțional subliniere este, este în cele din urmă repetate.
Casimir et Hippolyte

Nu-i asa, poate cineva sa rescrie regex? Nu părea să fi reușit să actualizare (versiunea de test a avut încă ? în loc de *)....
Maarten Bodewes

Multumesc din nou, am postat un raspuns care analizează întreg, precum și folosind expresia regulată sintaxă bazată în spiritul pe regex.
Maarten Bodewes
0

După răspunsul de la Cazimir-am decis să-l ia un pic mai departe și implementat un cod de fapt analiza numere întregi fel de bine, sunt incluse mai jos. Aceasta nu include minus și plus simboluri, chiar dacă acestea sunt în mod oficial nu face parte din întreg literal așa cum este descris în JLS; ele sunt operatorii unari.

package nl.owlstead.ifprops;

import java.math.BigInteger;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class JavaIntegerParser {
    private static final Pattern BINARY = Pattern.compile("(0b)([01](?:_*[01])*)(L?)", Pattern.CASE_INSENSITIVE);
    private static final Pattern OCTAL = Pattern.compile("(0)([0-7](?:_*[0-7])*)(L?)", Pattern.CASE_INSENSITIVE);
    private static final Pattern DECIMAL = Pattern.compile("()(0|(?:[1-9](?:_*[0-9])*))(L?)", Pattern.CASE_INSENSITIVE);
    private static final Pattern HEXADECIMAL = Pattern.compile("(0x)([0-9a-f](?:_*[0-9a-f])*)(L?)", Pattern.CASE_INSENSITIVE);
   
    // NOTE: OCTAL should be before DECIMAL if this is used to find the pattern
    private static final Pattern SIGNED_INTEGER_LITERAL = Pattern.compile(
            "(?:([+-])\\s*)?(" + 
            BINARY + "|" + OCTAL + "|" + DECIMAL + "|" + HEXADECIMAL + 
            ")", Pattern.CASE_INSENSITIVE);
        
    public static int parseJavaInteger(String javaInteger) throws NumberFormatException {
        BigInteger value = parseIntegerAsBigInt(javaInteger);
        try {
            return value.intValueExact();
        } catch (@SuppressWarnings("unused") ArithmeticException e) {
            throw new NumberFormatException("Number is not between Integer.MIN_VALUE and Integer.MAX_VALUE");
        }
    }
    
    public static long parseJavaLong(String javaLong) throws NumberFormatException {
        BigInteger value = parseIntegerAsBigInt(javaLong);
        try {
            return value.longValueExact();
        } catch (@SuppressWarnings("unused") ArithmeticException e) {
            throw new NumberFormatException("Number is not between Integer.MIN_VALUE and Integer.MAX_VALUE");
        }
    }

    private static BigInteger parseIntegerAsBigInt(String javaLiteral) {
        Matcher intMatcher = SIGNED_INTEGER_LITERAL.matcher(javaLiteral);
        if (!intMatcher.matches()) {
            throw new NumberFormatException(javaLiteral + " is not recognized as a Java integer literal");
        }
        
        String signGroup = intMatcher.group(1);
        String prefixAndValueGroup = intMatcher.group(2);
        String radixGroup = "";
        String valueGroup = "";
        // String longGroup = "";
        List<Pattern> patterns = List.of(BINARY, OCTAL, DECIMAL, HEXADECIMAL);
        for (Pattern pattern : patterns) {
            Matcher specificMatcher = pattern.matcher(prefixAndValueGroup);
            if (specificMatcher.matches()) {
                radixGroup = specificMatcher.group(1);
                valueGroup = specificMatcher.group(2);
                // longGroup = specificMatcher.group(3);
                break;
            }
        }
        
        if (valueGroup == null) {
            throw new RuntimeException("Number both matches but doesn't contain a value (parser error)");
        }

        BigInteger sign = signGroup != null && signGroup.matches("-") ? BigInteger.ONE.negate() : BigInteger.ONE; 
        
        int radix;
        switch (radixGroup.toLowerCase()) {
        case "0b":
            radix = 2;
            break;
        case "0":
            radix = 8;
            break;
        case "":
            radix = 10;
            break;
        case "0x":
            radix = 16;
            break;
        default:
            throw new RuntimeException();
        }
 
        BigInteger value = new BigInteger(valueGroup.replaceAll("_", ""), radix).multiply(sign);
        return value;
    }
}

Am încercat de asemenea să utilizați codul pentru a găsi mai multe numere întregi dintr-un șir, dar care nu a mers bine. Problema este că unele invalid literale cum ar fi 0__0 a fost acceptat ca doi literali cu valoarea zero; nu exact ceea ce vrei. Deci, vă rugăm să folosiți regex numai pentru a detecta dacă un șir este de fapt un întreg și separat intregi de exemplu, folosind String.split(SEPARATOR_REGEX).

Destul de amuzant mea Eclipse IDE făcut-o să accepte 0__0 ca un literal chiar dacă oficial nu mai este compatibil la JLS. Nu-i cine știe ce, dar ciudat nici unul-la-mai puțin.

2021-11-23 22:27:00

Vizualiza rapid răspunsul tău, îmi pare rău prea obosit pentru a merge mai adânc, dar: aveți grijă să nu folosiți prea mult surprinde, în special dacă nu aveți nevoie de ele. Utilizarea non-captarea grupuri (?:....) (surprinde au un cost).
Casimir et Hippolyte

Eu nu folosesc non-capturarea grupurilor acolo unde este posibil. Poate pentru a valida întreaga întreg I-ar putea elimina câteva; nu am nevoie de ele pentru meciul inițială. Sau poate am putea elimina întreaga inițială meci și lasă bucla care validează toate formatele posibile. Dar hei, până la urmă, suntem încercarea de a se potrivi numere întregi, nu pagini și pagini de text...
Maarten Bodewes
-1

Ei bine.... în termeni simpli, baza 2, 8, și 10 numărul ar putea folosi același model, deoarece valorile lor sunt caractere numerice. DAR, probabil că doriți o expresie pentru fiecare tip. Problema este că nu ați făcut clară intenția ta. Eu merg pe ipoteza că vrei expresia pentru a valida ceea ce bază o anumită valoare.

String base10Regex = "[0-9]+";
String base2Regex = "[0-1]+";
String base8Regex = "[0-7]+";
String base16Regex = "^[0-9A-F]+$";

Pentru octal și valori zecimale, va trebui să adauge expresia ta de a verifica pentru un opțional semn caracter "^[\\+|-]?". Pentru valori hex, daca crezi ca valorile să înceapă cu "0x", eu va sugerez sa se adauge expresia cu aceste valori literale.

2021-12-09 23:34:58

Nu subliniază și nu se potrivește cu efective de numere întregi. Și, desigur, limitele (^$) nu ar lucra cu, dar este un început...
Maarten Bodewes

@MaartenBodewes Mulțumesc. Am acorda subliniaza, dar ce vrei sa spui ca nu se potrivesc reale numere întregi? De asemenea, nu știam că limitele nu funcționează cu find. Deci, vă mulțumesc pentru că la fel de bine.
hfontanez

Scuze, greseala mea, am vrut să spun că nu se potrivește cu literali cum este indicat în JLS, în cazul în care aveți nevoie pentru a avea 0x sau 0X pentru hexadecimals etc.
Maarten Bodewes

@MaartenBodewes cu excepția am scris " dacă te aștepți ca valorile să înceapă cu "0x", eu va sugerez sa se adauge expresia cu aceste valori literale"
hfontanez

În alte limbi

Această pagină este în alte limbi

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................