Какое регулярное выражение для проверки текстового поля JavaFX для десятичного числа в нотации scientifi c - PullRequest
0 голосов
/ 13 июля 2020

Используя в качестве отправной точки класс DecimalField, найденный на этом сайте, я написал следующее:

import javafx.scene.control.TextField;
import java.util.regex.Pattern;

public class DecimalField extends TextField {

    public Boolean rate, positive, integer;
    Pattern decimalPattern;

    DecimalField(Boolean rate, Boolean positive) {
        this.rate = rate;
        this.positive = positive;
        decimalPattern = Pattern.compile ("[-+]?[0-9]*(\\.[0-9]*)?");
//        decimalPattern = Pattern.compile("[-+]?(\\b[0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+\\b)?");
        if (rate) {
            decimalPattern = Pattern.compile ("[-+]?[0-9]*(\\.[0-9]*)?[%]?");
        } else if (positive) {
            decimalPattern = Pattern.compile ("[1-9][0-9]*(\\.[0-9]*)?");
        }
    }

    @Override
    public void replaceText(int start, int end, String text) {
        if (validate (start, text)) {
            super.replaceText (start, end, text);
        }
    }

    @Override
    public void replaceSelection(String text) {
        if (validate (Integer.MAX_VALUE, text)) {
            super.replaceSelection (text);
        }
    }

    private boolean validate(int start, String text) {
        String currentText = (getText ().isEmpty ()) ? "" : getText ();
        if (start == 0) { //to handle "-1.1" or ".1" cases
            return decimalPattern.matcher (text + currentText).matches ();
        } else {
            return decimalPattern.matcher (currentText + text).matches ();
        }
    }

}

В зависимости от параметров, отправленных в конструктор, этот класс можно использовать для ограничения записей стандартным десятичное число, только положительное (т. е.> 0) десятичное число или число, за которым следует символ процента. Кажется, он работает нормально (предоставляется небольшое тестовое приложение), но я также хотел иметь возможность указать число в нотации scientifi c, например 25.56e-5. Я не мог написать правильный шаблон регулярного выражения. Такой шаблон, как «[0-9.eE + -] *» ограничил бы ввод допустимыми символами, но не обеспечил бы принудительный синтаксис числа! Предложения приветствуются.

Вот тестовая программа:

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class DecimalFieldTest extends Application {
    @Override
    public void start(Stage primaryStage) {
//        Boolean rate;
//        rate = false; positive = true;
        Label basicLbl = new Label("Basic Decimal");
        DecimalField decimalField = new DecimalField (false, false);
        Label rateLbl = new Label("Rate Decimal");
        DecimalField rateDecimalField = new DecimalField (true, false);
        Label positiveLbl = new Label("Positive Decimal");
        DecimalField positiveDecimalField = new DecimalField (false, true);
        Button clickMe = new Button ("Click Me");
        clickMe.setOnAction (new EventHandler<ActionEvent> () {
            @Override
            public void handle(ActionEvent event) {
                String s;
                s = decimalField.getText ();
                if (!s.isEmpty ()) getOut(s, false);
                s = rateDecimalField.getText ();
                if (!s.isEmpty ()) getOut(s, true);
                s = positiveDecimalField.getText ();
                if (!s.isEmpty ()) getOut(s, false);
            }
        });
        decimalField.setOnAction (new EventHandler<ActionEvent> () {
            @Override
            public void handle(ActionEvent event) {
                getOut(decimalField.getText (),false);
            }
        });
        rateDecimalField.setOnAction (new EventHandler<ActionEvent> () {
            @Override
            public void handle(ActionEvent event) {
                getOut(rateDecimalField.getText (),true);
            }
        });
        positiveDecimalField.setOnAction (new EventHandler<ActionEvent> () {
            @Override
            public void handle(ActionEvent event) {
                getOut(positiveDecimalField.getText (),false);
            }
        });
        VBox root = new VBox (5, basicLbl, decimalField,
                rateLbl, rateDecimalField, positiveLbl, positiveDecimalField, clickMe);
        root.setAlignment (Pos.CENTER);
        Scene scene = new Scene (root, 300, 250);
        primaryStage.setScene (scene);
        primaryStage.show ();
    }

    void getOut(String s, Boolean rate) {
        // for rate : textField.getText().replaceAll("%","")
        String ss = s.replaceAll ("%", "");
        double value = Double.parseDouble (ss);
        if (rate) {
            System.out.println (String.format (ss + " <-> " + value) + "%");
        } else {
            System.out.println (String.format (ss + " <-> " + value));
        }
    }

    public static void main(String[] args) {
        launch (args);
    }
}

1 Ответ

0 голосов
/ 14 июля 2020

Вы можете использовать NumberTextField с BigDecimal и другими числовыми форматами.

package control;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.control.TextField;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.ParseException;

/**
 * Number text field
 * 
 * <p>
 * Original source code from:
 * https://dzone.com/articles/javafx-numbertextfield-and
 */
public class NumberTextField extends TextField {

    private final NumberFormat numberFormat;
    private ObjectProperty<BigDecimal> value = new SimpleObjectProperty<>();

    public NumberTextField(NumberFormat numberFormat) {
        this(BigDecimal.ZERO, numberFormat, 100);
    }

    public NumberTextField(NumberFormat numberFormat, double width) {
        this(BigDecimal.ZERO, numberFormat, width);
    }

    /**
     * Number field with properties.
     *
     * @param value        decimal value
     * @param numberFormat number format
     * @param width        min, max and pref width
     */
    public NumberTextField(BigDecimal value, NumberFormat numberFormat, double width) {
        super();
        this.numberFormat = numberFormat;
        setMinWidth(width);
        setMaxWidth(width);
        setPrefWidth(width);
        initHandlers();
        setValue(value);
        setAlignment(Pos.BOTTOM_RIGHT);
    }

    public final BigDecimal getValue() {
        return value.get();
    }

    public final void setValue(BigDecimal value) {
        this.value.set(value);
    }

    public ObjectProperty<BigDecimal> valueProperty() {
        return value;
    }

    private void initHandlers() {
        // try to parse when focus is lost or RETURN is hit
        setOnAction((ActionEvent arg0) -> {
            parseAndFormatInput();
        });

        focusedProperty().addListener((ObservableValue<? extends Boolean> observable,
                                       Boolean oldValue, Boolean newValue) -> {
            if (!newValue) {
                parseAndFormatInput();
            }
        });

        // Set text in field if BigDecimal property is changed from outside.
        valueProperty().addListener((ObservableValue<? extends BigDecimal> observable,
                                     BigDecimal oldValue, BigDecimal newValue) -> {
            setText(numberFormat.format(newValue));
        });
    }

    /**
     * Tries to parse the user input to a number according to the provided
     * NumberFormat
     */
    private void parseAndFormatInput() {
        try {
            String input = getText();
            if (input == null || input.length() == 0) {
                return;
            }
            Number parsedNumber = numberFormat.parse(input);
            BigDecimal newValue = new BigDecimal(parsedNumber.toString());
            setValue(newValue);
            selectAll();
        } catch (ParseException ex) {
            // If parsing fails keep old number
            setText(numberFormat.format(value.get()));
        }
    }
}

И как BigDecimalTextField:

NumberTextField bigDecimalField = 
    new NumberTextField(new DecimalFormat("#,###,###,##0.00"));
...