Search code examples
regexbashsh

RegExp testing fails when string is validated in RegExp tools


I have a small regexp that should verify if a commits subject adheres to the ReactJS commit message format. Since the expression works with my test strings the code left me baffled.

This small example should reproduce the behaviour:

#!/bin/bash

function test_subject {
  local subject="$1"
  local pattern="^(feat|fix|docs|style|refactor|test|chore)\([a-zA-Z0-9._-]+\): [^\n]+$"

  if ! [[ $subject =~ $pattern ]]; then
    echo "Invalid subject: $subject"
  else
    echo "  Valid subject: $subject"
  fi
}

test_subject "chore(gh-actions): add script for commit check"
test_subject "chore(gh-actions): add script for commit checking"
test_subject "feat(ABC-123): add new feature"
test_subject "fix(ABC123): add new feature"
test_subject "fix(ABC123): fix previously added feature"
test_subject "fix(scope): fix bug"

This leads to the following output:

  Valid subject: chore(gh-actions): add script for commit check
Invalid subject: chore(gh-actions): add script for commit checking
Invalid subject: feat(ABC-123): add new feature
Invalid subject: fix(ABC123): add new feature
  Valid subject: fix(ABC123): fix previously added feature
  Valid subject: fix(scope): fix bug

Solution

  • You will need to use . instead of [^\n] in your shell regex to match any character.

    rx="[^\n]" doesn't mean any character except newline. It is seeing \ and n as two separate characters hence [^\n] is seen as any character other than \ and n.

    Note that your example strings number 2, 3, and 4 have the letter n somewhere after matching : hence it is not matching till end of line and $ assertion in the end fails the match.

    This should work for you:

    test_subject() {
      local subject="$1"
      local pattern="^(feat|fix|docs|style|refactor|test|chore)\([a-zA-Z0-9._-]+\): .+$"
    
      if ! [[ $subject =~ $pattern ]]; then
        echo "Invalid subject: $subject"
      else
        echo "  Valid subject: $subject"
      fi
    }
    
    test_subject "chore(gh-actions): add script for commit check"
    test_subject "chore(gh-actions): add script for commit checking"
    test_subject "feat(ABC-123): add new feature"
    test_subject "fix(ABC123): add new feature"
    test_subject "fix(ABC123): fix previously added feature"
    test_subject "fix(scope): fix bug"
    

    Output:

    Valid subject: chore(gh-actions): add script for commit check
    Valid subject: chore(gh-actions): add script for commit checking
    Valid subject: feat(ABC-123): add new feature
    Valid subject: fix(ABC123): add new feature
    Valid subject: fix(ABC123): fix previously added feature
    Valid subject: fix(scope): fix bug