Search code examples
javascriptregexclient-side-validation

Only limit one period/decimal in field (client-side validation) Regex - JavaScript


I have a client-side validation function in JavaScript for a field Value that allows the user to enter-in a dollar amount. The validation works perfect (only allows numbers and periods/decimals to be inputted) into the field. All other characters are simply deleted. I like to update the function where it allows only one decimal/period to be inputted, any more than one will be deleted

Here is what I have so far:

onkeyup="if (!RegExp(/^\d*\.?\d*$/).test(this.value)) { this.value = this.value.replace(RegExp(/[A-Za-z-!$%^&*()_+|~=`{}\[\]:;'<>?,\/]+/).exec(this.value), '').replace(String.fromCharCode(34), '');}"

Any help/suggestion would be great!


Solution

    1. Don't stuff everything into the HTML event attribute. Write a function! That also removes the necessity to use String.fromCharCode(34) just to get a double quote character.

      BTW, if you do need a double quote character inside a HTML attribute just use &quot;.

    2. RegExp(/^\d*\.?\d*$/) is duplicated. Just use /^\d*\.?\d*$/, because it is already an regular expression. RegExp is used if you want to convert a string into regular expression like this: RegExp("^\\d*\\.?\\d*$").

    3. Calling .exec() and using it as an argument for .replace() makes no sense. .exec() returns an array (containing matches), but .replace() needs a regular expression (or a string) as it's first parameter. Also you need to add the g(lobal) flag to the expression or only the first match will be replaced

      this.value = this.value.replace(/[A-Za-z-!$%^&*()_+|~=`{}\[\]:;'<>?,\/"]+/g, '');
      

      Notice I added the double quote character into the regular expression. However it may be easier just to replace everything that is not a digit or a period:

      this.value = this.value.replace(/[^\d.]/g, '');
      

    Deleting additional periods can't be done with regular expression alone (at least not in all current browsers). One way to do it would be to .split the string at the periods and then join it back together with just the period between the first and second items:

    function removeAllButFirstPeriod(string) {
      const split = string.split(".");
      if (split.length === 1) {
        // If the split string contains only one element, then there were no periods in the string
        return split[0];
      } else {
        return split[0] + "." + split.slice(1).join(""); 
      }
    }
    

    (See also .slice() and .join())

    End result (the .test isn't needed. Just always remove all invalid chars):

    function removeInvalidNumberChars(element) {
      element.value = removeAllButFirstPeriod(element.value.replace(/[^\d.]/g, ''));
    }
    

    with (the input event is a better choice than keydown)

    <input oninput="removeInvalidNumberChars(this)">