google-apps-scriptgoogle-forms

Google Forms set regular expression in Apps Script


I'm making a Google Form via Apps Script and need to set a field to only accept US 10-digit phone numbers. I found this regular expression which works if I set it via the Form Editor: ^(\+0?1\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$.

But again, I need this to work from Apps Script. My code snippet is as follows:

let form = FormApp.create("new Order");
let phoneNumber = form.addTextItem().setTitle("Textable phone number").setRequired(true);
  phoneNumber.setValidation(FormApp.createTextValidation()
      .requireTextMatchesPattern("^(\+0?1\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$")
      .build());

This throws Exception: Invalid data updating form. When I change it to .requireTextMatchesPattern(/^(\+0?1\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/) the script runs and completes, but then it's impossible to fill out the form because a standard phone number throws an error saying must match pattern.

So, how do I set a regular expression pattern in Apps Script that will properly allow input?


Solution

  • Escaping special characters in regexes

    That question refers to the requireTextMatchesPattern() method that expects a regex string rather than a RegExp object. The problem is that Javascript strings and regexes both use the backslash \ to escape certain special characters, but not all the escapes have the same meaning in the two contexts.

    There are many special characters in regular expressions, including:

    .*+?^${}()|[]\
    

    The regex in the question uses some of those characters literally, such as searching for an instance of +. To do that, you must escape the special character by adding a backslash \ prefix. That is easy to do when you use a JavaScript regex literal, but more tricky when you need to use a JavaScript string literal. Notably, to get an actual backslash in a JavaScript string literal, you need to escape it as in \\.

    Since the string regex requires backslashes, you need to double those backslashes in the JavaScript string in order for them to be interpreted correctly. To get the regex string ^(\+0)$, where + is a literal rather than a special character, you need to use the JavaScript string '^(\\+0)$'.

    To make the regex string work, do the same with all special characters you need to escape in the string, like this:

    function getFormWithRegexValidation() {
      const phoneNumberPattern = '^(\\+0?1\\s)?\\(?\\d{3}\\)?[-.\\s]\\d{3}[-.\\s]\\d{4}$';
      const phoneNumberValidation = FormApp.createTextValidation()
        .requireTextMatchesPattern(phoneNumberPattern)
        .build();
      const form = FormApp.create('new Order');
      form.addTextItem()
        .setTitle('Textable phone number')
        .setRequired(true)
        .setValidation(phoneNumberValidation);
      return form;
    }
    

    In the event you're not working with string literals but need to escape all regex special characters in a string variable, for example in the input received from a user, use this utility function:

    /**
    * Escapes special characters such as \ ( ) [ ].
    *
    * @param {String} string The text string to escape.
    * @return {String} The escaped text string.
    */
    function escapeRegExCharacters_(string) {
      // version 1.1, written by --Hyde, 9 November 2018
      //  - adapted from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
      return String(string).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
    }
    

    See Using special characters in strings.