Yerlan Yeszhanov
Yerlan Yeszhanov

Reputation: 2439

How to make proper Input validation with regex?

I want let users enter only integer or floating numbers. Right now I can only enter integer numbers,it does allow type dot or comma . Cant find proper regex to validate both integer and floating numbers.

<input
  type="text"
  id="depositedAmount"
  maxLength={9}
  placeholder="Enter amount"
  onChange={(e) => this.handleInputChange(e, currentComProfile)}
  value={depositedAmount}
/>

handleInputChange=(e, currentComProfile) => {
    const re = /^[+-]?\d+(\.\d+)?$/;

    if (e.target.value === '' || re.test(e.target.value)) {
      if (e.target.id === 'depositedAmount') {
        this.props.updateDepositedAmount(e.target.value, currentComProfile);
      }
      if (e.target.id === 'willBeCreditedAmount') {
        this.props.updateWillBeCreditedAmount(e.target.value, currentComProfile);
      }
    }
  }

Upvotes: 2

Views: 5010

Answers (3)

Kresimir Nenadic
Kresimir Nenadic

Reputation: 13

function App() {

    const [budget, setBudget] = useState(0);

    const handleKeyPress = (ev) => {
        let charC = (ev.which) ? ev.which : ev.keyCode;
        if(charC == 46) {
            if(ev.target.value.indexOf('.') === -1) {
                let caretPos = ev.target.selectionStart;
                if(caretPos <= (ev.target.value.length - 3)) {
                    ev.preventDefault();
                    return false;
                }
                return true;
            }
            else {
                ev.preventDefault();
                return false;
            }
        }
        else {
            if(charC > 31 && (charC < 48 || charC > 57)) {
                ev.preventDefault();
                return false;
            }
        }

        if(ev.target.value.indexOf('.') !== -1) {
            let numComp = ev.target.value.split('.');                    
            if(numComp[1].length > 1) {
                let caretPos = ev.target.selectionStart;
                let dotPos = ev.target.value.indexOf('.');
                if(caretPos <= dotPos) {
                    return true;
                }
                ev.preventDefault();
                return false;
            }
        }                
        return true;
    }

    const handleChange = (ev) => {
        setBudget(ev.target.value);
    }

    return (
        <div className="App">
            <div className="input-control">
                <label>
                    Iznos proračuna: 
                    <input 
                        type="text"
                        value={budget}
                        onKeyPress={(event) => handleKeyPress(event) }
                        onChange={(event) => handleChange(event)}
                    />
                </label>
            </div>
        </div>
    );
}
export default App;

Explanation: React is a bit different than 'pure' JavaScript. 'handlePress' function is like already suggested solutions in pure JavaScript but instead returning 'false' one should use ev.preventDefault() prior to returning false to prevent displaying unwanted characters. Displaying decimal dot is allowed only once in input field and input is limited to max 2 decimal places, so decimal point can be in front of max 2 last digits on the right. Code can be customized for other purposes as well :)

Upvotes: 0

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626738

You may use

const rx_live = /^[+-]?\d*(?:[.,]\d*)?$/;

for live validation. For the final validation, use

const rx_final = /^[+-]?\d+(?:[.,]\d+)?$/;

Or, better, just use the regex in the pattern attribute: pattern="[+-]?\d*(?:[.,]\d*)?".

NOTE

  • ^ - start of string
  • [+-]? - an optional + or -
  • \d* - 0 or more digits
  • (?:[.,]\d*)? - an optional sequence of . or , and then 0 or more digits
  • $ - end of string.

In final validation, \d+ is used instead of \d* to match one or more digits as opposed tozero or more digits.

See the JS demo:

const rx_live = /^[+-]?\d*(?:[.,]\d*)?$/;

class TestForm extends React.Component {
  constructor() {
    super();
    this.state = {
      depositedAmount: ''
    };
  }

  handleDepositeAmountChange = (evt) => {
    if (rx_live.test(evt.target.value))
        this.setState({ depositedAmount : evt.target.value });
 }
  
  render() {
    return (
      <form>
       <input
        type="text"
        id="depositedAmount"
        maxLength={9}
        pattern="[+-]?\d+(?:[.,]\d+)?"
        placeholder="Enter amount"
        onChange={this.handleDepositeAmountChange}
        value={this.state.depositedAmount}
       />
      </form>
    )
  }
}


ReactDOM.render( < TestForm /> , document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Upvotes: 1

JoshG
JoshG

Reputation: 6735

Your regex should match dots, but it doesn't seem to match commas. You could try something like:

^[0-9]+([,.][0-9]+)?$

For reference:

[0-9] matches digits 0-9.

+ matches between one and unlimited times, as many times as possible.

[,.] matches comma or dot.

There might be a way to simplify this regex, but I think it should work.

You can test it here: https://regex101.com/r/V0J63U/1

--Update--

To match leading signs also (i.e., +/-), you can add ^[+-]? to the beginning of the pattern:

^[+-]?[0-9]+([,.][0-9]+)?$

You can test it here: https://regex101.com/r/cQylX3/1

Thank you to @CodeManiac for the tips!

Upvotes: 0

Related Questions