Wyrażenie regularne do zgodności целочисленному литералу

0

Pytanie

Myślałem o analizie listy liczb całkowitych (z paska właściwości). Jednak chciałbym wyjść poza tylko pozytywnych i negatywnych wartości dziesiętnych i analizować dowolny ciąg znaków, który wskazuje na całkowitą literał Java (JLS 17), jak to można znaleźć w kodzie źródłowym. Podobnie, chciałbym być wyrozumiali w stosunku do wszystkich prefiksów, zakładek i aplikacji wokół samych liczb całkowitych. Innymi słowy, chcę je znaleźć przy użyciu powtarzające się rozmowy wMatcher.find().

Czy istnieje wyrażenie regularne, które odpowiada na wszystkie możliwe której литералам Java? Nie musi sprawdzać górną i dolną granice.


Mimo, że jestem wyraźnie nawiązywał do JLS, pokażę niektóre prawidłowe i nieprawidłowe numery:

  • -1: w 1 odpowiada, ale minus-operatora jednoargumentowego (ja скорректирую, jeśli to konieczne)
  • 0x00_00_00_0F: wartość piętnaście jest mapowany w postaci cyfr szesnastkowych z podkreśleniem do oddzielenia dwóch kawałków
  • 0b0000_1111: wartość piętnaście w formacie binarnym odpowiada
  • 017: ósemkowe wartość piętnaście odpowiada
integer java literals regex
2021-11-23 21:48:28
3

Najlepsza odpowiedź

4

Coś w tym stylu:

dziesiętny:
(?:0|[1-9](?:_*[0-9])*)[lL]?

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

восьмеричный:
0[0-7](?:_*[0-7])*[lL]?

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

Wszyscy razem: (w trybie wolnego miejsca)

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

sprawdź to

2021-11-23 22:47:19

O tak, to by mnie przejść długą drogę. Jednak dopuszcza się czy to kilka podkreślenia? Może być to ? powinno być *?
Maarten Bodewes

@MaartenBodewes: rozumiem, że w dokumencie podkreślenia nie powinny być łączone, ale może się mylę? (innymi słowy, jest to 1____1 dozwolone ?). Należy pamiętać, że grupa, w której znajduje się opcjonalna podkreślenie, że w końcu się powtarza.
Casimir et Hippolyte

Ha, ktoś może przepisać to wyrażenie regularne? Wydawało mi się, że udało mi się go zaktualizować (w wersji testowej wciąż był ? zamiast *)....
Maarten Bodewes

Jeszcze raz dziękuję, jestem opublikował odpowiedź, w którym analizowana jest liczba całkowita z użyciem składni wyrażenia regularnego, założonego w duchu danego wyrażenia regularnego.
Maarten Bodewes
0

Po odpowiedzi Kazimierza postanowiłem pójść nieco dalej i wykorzystał jakiś kod do rzeczywistej analizy liczb całkowitych, który znajduje się poniżej. Zawiera on znaki minus i plus, choć oficjalnie nie są one częścią dotyczący literału, jak opisano w JLS; są one унарными operatorami.

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;
    }
}

Próbowałem też użyć kodu, aby wyszukać kilka liczb całkowitych z polecenia, ale to nie zadziałało. Problem w tym, że niektóre nieprawidłowe literały, takie jak 0__0 został przyjęty jako dwa literału z zerową wartością; nie do końca to, co chcesz. Więc proszę, użyj wyrażenie regularne tylko do określenia, czy ciąg jest w rzeczywistości liczbą całkowitą, i podzielenie liczby, na przykład, za pomocą String.split(SEPARATOR_REGEX).

Zabawne, że moja środowisko programistyczne Eclipse przyjęła 0__0 dosłownie, nawet jeśli oficjalnie nie odpowiada JLS. Nie duży, ale jednak dziwny.

2021-11-23 22:27:00

Szybko sprawdź swoją odpowiedź, przepraszam, że jest zbyt zmęczony, aby zagłębiać, ale uważaj, aby nie używać zbyt dużo zdjęć, w szczególności, jeżeli nie są potrzebne. Użyj grupy bez przechwytywania (?:....) (uchwyty mają określoną wartość).
Casimir et Hippolyte

Używam grupy bez przechwytywania, gdzie jest to możliwe. Być może, w celu sprawdzenia całego liczby mógłbym usunąć kilka; oni mi nie są potrzebne do pierwotnego mapowania. Lub, być może, mógłbym usunąć wszystkie początkowe zbieg okoliczności i po prostu zostawić cykl, który sprawdza wszystkie możliwe formaty. Ale hej, w końcu staramy się dopasować liczby, a nie strony i strony tekstu...
Maarten Bodewes
-1

Cóż ... mówiąc prościej, podstawowe liczby 2, 8 i 10 mogą korzystać z tego samego szablonu, ponieważ wszystkie ich wartości numerycznych są symbolami. ALE, prawdopodobnie, trzeba wyrażenie dla każdego typu. Problem w tym, że nie wyjaśnić swoje intencje. Wychodzę z założenia, że chcesz, aby wyrażenie proveryalo, na jakiej podstawie jest konkretna wartość.

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

Dla восьмеричных i dziesiętnych wartości trzeba będzie dodać swój wyraz, aby sprawdzić, czy opcjonalnego znaku towarowego "^[\\+|-]?". Dla szesnastkowych wartości, jeśli można się spodziewać, że wartości będą zaczynać się od "0x", ja proponuję dodać do wyrażenia te dosłowne znaczenia.

2021-12-09 23:34:58

Bez podkreślenia, i nie jest zgodna z rzeczywistą liczbą liczb. I, oczywiście, granice (^$nie będzie działać z find, ale to dopiero początek...
Maarten Bodewes

@MaartenBodewes Dziękuję ci. Daję ci podkreślenie, ale co masz na myśli, że nie jest ono zgodne z rzeczywistą liczbą liczb? Poza tym, nie wiedziałem, że granice nie działają find. Tak, że dziękuję i za to.
hfontanez

Przepraszam, mój zły, miałem na myśli, że nie spełnia литералам określonych w JLS, gdzie trzeba mieć 0x lub 0X dla szesnastkowych itp.
Maarten Bodewes

@MaartenBodewes za wyjątkiem tego, że napisałem: "jeśli można się spodziewać, że wartości będą zaczynać się od "0x", ja proponuję dodać do wyrażenia te dosłowne znaczenia".
hfontanez

W innych językach

Ta strona jest w innych językach

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