Write it first

When it comes to regular expressions, many of your friends react along the lines of “Better not use that thing, it can’t be maintained!” , “Too complicated, not often used, can not learn”…. Admittedly, the regular expression is a little hard to understand. If one day you’re maintaining a piece of code, and you’re curious enough to open the code file, a lot of it looks like this:

letfunCallRegExp = /(^(\s+)? (((? ! (class|function))([a-zA-Z_][a-zA-Z0-9_]*))(\(((\s+)? ((? ! (class|function))([a-zA-Z_][a-zA-Z0-9_]*))(\s+)?) (,((\s+)? ((? ! (class|function))([a-zA-Z_][a-zA-Z0-9_]*))(\s+)?) )*\)))(\s+)? (,(\s+)? (((? ! (class|function))([a-zA-Z_][a-zA-Z0-9_]*))(\(((\s+)? ((? ! (class|function))([a-zA-Z_][a-zA-Z0-9_]*))(\s+)?) (,((\s+)? ((? ! (class|function))([a-zA-Z_][a-zA-Z0-9_]*))(\s+)?) )*\)))(\s+)?) *)$/gm;Copy the code

sum(param1, param2), avg(score)
Copy the code

There are nearly 30 cases listed below that describe various restrictions on this syntax:

describe("validate", () => {
  it("Calls to different methods are separated by commas, which may or may not be separated by Spaces.", () => {
    expect(validate("sum(param1),avg(score)")).toBe(true);
    expect(validate("sum(param1) ,avg(score)")).toBe(true);
    expect(validate("sum(param1) , avg(score)")).toBe(true);
    expect(validate("sum(param1) avg(score)")).toBe(false);
    expect(validate("sum(param1)avg(score)")).toBe(false);
  });
  it("No commas or extraneous words (except Spaces) should appear at the beginning or end of the entire statement.", () => {
    expect(validate(" sum(param1),avg(b)")).toBe(true);
    expect(validate(" sum(param1),avg(b) ")).toBe(true);
    expect(validate("sum(param1),avg(b) ")).toBe(true);
    expect(validate("a sum(test),avg(a)")).toBe(false);
    expect(validate(" sum(param1),avg(b)12")).toBe(false);
    expect(validate("sdf sum(param1),avg(b) sdf")).toBe(false);
  });
  it("Function name & argument: starts with a letter or underscore and may consist of alphanumeric underscores.", () => {
    expect(validate("sum(a)")).toBe(true);
    expect(validate("sum(a0)")).toBe(true);
    expect(validate("_sum(a0)")).toBe(true);
    expect(validate("_sum0(_a0)")).toBe(true);
    expect(validate("_sum0(_)")).toBe(true);
    expect(validate("_sum0(1)")).toBe(false);
    expect(validate("_sum0(1a)")).toBe(false);
    expect(validate("2aa(a)")).toBe(false);
  });
  it("The function name & parameters: cannot contain reserved word class | | function." ", () => {
    expect(validate("afunctiona(a,b)")).toBe(true);
    expect(validate("functiona(a,b)")).toBe(true);
    expect(validate("class(a), a(a,b)")).toBe(false);
    expect(validate("function(a,b)")).toBe(false);
    expect(validate("function(a,b)")).toBe(false);
    expect(validate("sum(a,function)")).toBe(false);
    expect(validate("sum(class,b)")).toBe(false);

    expect(validate("class1(a,b)")).toBe(true);
    expect(validate("function1(a,b)")).toBe(true);
  });
  it("There can be Spaces between parameters.", () => {
    expect(validate("sum(a ,b ,c)")).toBe(true);
    expect(validate("sum( a , b ,c)")).toBe(true);
    expect(validate("sum( a , b ,c) , avg(d,e , fff)")).toBe(true);
  });
  it("Function call can pass no arguments", () => {
    expect(validate("sum()")).toBe(true);
    expect(validate("sum( )")).toBe(true);
  });
});

Copy the code

The more complex a problem is, the more it needs to be disassembled and converted into a series of simple sub-problems. With these simple sub-problems, we can easily give solutions using re, and then combine these solutions one by one to form the final solution.

Here, we can break down what we need to verify into the following sections:

Space = Contains zero or more Spaces. 1. Parameter = Contains letters, digits, or underscores (_) and starts with a letter or underscore (_). Non-reserved word arguments = arguments && do not contain keywords 3. Can contain Spaces = Non-reserved word arguments && Can have zero or more Spaces at the beginning and end 4. Parameter set = a combination of multiple parameters, which can be 1 or more 5. Sum () or sum() 6. Function name = unreserved word argument 7. Function call = function name + argument block 8. Function calls that can contain Spaces = function calls that can have zero or more Spaces at the beginning and end 9. Multiple function calls = a combination of multiple function calls, one or more of which may occur 10. End result = multiple function calls && the header and tail contain nothing but Spaces

With the above ideas, the verification scheme is ready to come out, post the code:

functionValidate (inputStr) {// 0. Space = 0 or more Spaces const spaceOrEmpty = '*'; Const param = '[A-za-z_][A-za-z0-9_]*'; const param = '[A-za-z0-9_]*'; // Matches multiple Spaces or empty Spaces // 1. / / 2. No reserved word parameters = && does not contain the keywords const paramWithoutReservedWords = ` (? ! \\bclass\\b|\\bfunction\\b)(${param}) `; / / 3. = no reserved words can contain Spaces parameters parameters && end could be zero or more Spaces const paramWithSpaceWithoutReservedWords = `${spaceOrEmpty}${paramWithoutReservedWords}${spaceOrEmpty}`; // 4. Parameter set = multiple parameters, which can be 1 or more const params = '(${paramWithSpaceWithoutReservedWords}(,${paramWithSpaceWithoutReservedWords}) *) `; Sum () or sum() const paramsBlock = '\\(// const paramsBlock =' \\() const paramsBlock = '\\(${params}?${spaceOrEmpty}\ \) `; / / 6. The function name = no reserved word parameter const funName = paramWithSpaceWithoutReservedWords; // 7. Function call = function name + argument block const funCall =${funName}${paramsBlock}`; Function calls that can contain Spaces = function calls that can have zero or more Spaces at the beginning and end of a function call const funCallWithSpace = '${spaceOrEmpty}${funCall}${spaceOrEmpty}`; // 9. Multiple function calls = a combination of multiple function calls, in which one or more const multipleFunCall = 'may occur${funCallWithSpace}(,${funCallWithSpace}) * `; // 10. Final result = multiple function calls && with no header or tail except Spaces const finalFunCall = '^${multipleFunCall}$`;

  const reg = new RegExp(finalFunCall);
  return reg.test(inputStr);
}
Copy the code