0

I'm using AngularJS in here. I have no problem matching those words except "C++". Every time I type in "c++" as keyword to generate the RegExp in Javascript and run the matching, I get the error in console as below:

SyntaxError: Invalid regular expression: /(\bc++\b)/: Nothing to repeat

The code snippet is as below:

$scope.data = [
  {'title': 'Blue Java Programming Book'},
  {'title': 'Red C++ Programming Book'},
  {'title': 'Javascript Dummies Guide'}
  ];

$scope.submit = function() {
  $scope.length = $scope.keywords.split(" ").length;
  $scope.keywordsArray = $scope.keywords.split(" ");

  $scope.pattern = "";
  for (var y = 0; y < $scope.length; y++) {
    $scope.pattern += "(?=.*?\\b" + $scope.keywordsArray[y] + "\\b)";
  }
  $scope.pattern+=".*";
  $scope.patt = new RegExp($scope.pattern, "i");
  for (var x = 0; x < $scope.data.length; x++) {
    console.log("Match [" + x + "] " + $scope.patt.test($scope.data[x].description));
  }

}
<input type="text" ng-model="keywords"></input>
<button ng-click="submit()">Submit</button>

I understand that the + sign in RegExp is for matching one or more times of the preceding character, then I tried hardcode the RegExp as below to test and it matches, but not the way I wanted as I need the RegExp to be generated every time I key in the keywords.

$scope.regExp = /c\+\++/i

Is there any way to generate a RegExp on the fly with multiple keywords to match an array of data that includes "c++"?

3
  • I'm not 100% sure what your problem is but you can also represent c++ as c[\+]{2} Commented Jan 21, 2015 at 2:53
  • do you want to generate Regex for each keywords in the $scope.data? Commented Jan 21, 2015 at 3:17
  • @AnuragPeshne I wanted to generated Regex based on the keywords entered in the input and then search for matching ones at $scope.data Commented Jan 21, 2015 at 4:31

2 Answers 2

1

Considering that you'll collect input in var ip, you can try this:

rrexp = new RegExp('[\\+|\\^|\\-|\\||\\?|\\*|\\{|\\}|\\$]','g');
//rrexp contains all the special characters which need to be escaped

ip = 'c++';
var escapedExp = ip.replace(rrexp, function(fs, matched){
  return '\\'+fs;
});
/*
ip.replace will replace special characters in the 'ip' to be replaced by escaped version of them.
For Eg. + will replaced \\+. Thus 'c++' becomes 'c\\+\\+'
*/ 

var regEx = new RegExp(escapedExp, 'gi');
// this creates Regular Expression based on the ip which matches all exp and is case insensitive.

q = 'Red C++ Programming Book';
q.match(regEx);  //this should output: [ 'C++' ]

Edit

If you want to create multiple Regex, you can put ip.replace and new Regex in a loop. Sometime like

inputs = ['c++', 'simpleExp', 'complex$one'];
var escapedExp, regEx;
regexList = [];
inputs.forEach(function(ip) {
  escapedExp = ip.replace(rrexp, function(fs, matched){
    return '\\'+fs;
  });
  regEx = new RegExp(escapedExp, 'gi');
  regexList.push(regEx);
});
//regexList will contain all the Regex based on inputs

Edit 2: \b word boundary cannot match words with special characters.

A word boundary asserts that the position is either preceded by a word character and not followed by one, or followed by a word character and not preceded by one. Thus all the special characters except '_' will not recognised by \b.

I can suggest a hack: you need to figure out where in the keywords special characters can appear and then add \b according to it. If there are special character in the end of the keyword we cannot add \b after it similarly for start of the keyword. If both ends have normal characters then we can add \b to both ends.

Here's how I would do:

noBAtStart = false;
noBAtEnd = false;
var escapedExp = ip.replace(rrexp, function(matched, offset) {
  if(offset == 0)
    noBAtStart = true;
  if(offset == ip.length - 1)
    noBAtEnd = true;
  return '\\' + matched;
});

if(!noBAtStart)
  escapedExp = '\\b' + escapedExp;
if(!noBAtEnd)
  escapedExp = escapedExp + '\\b';

var regEx = new RegExp(escapedExp, 'gi');
Sign up to request clarification or add additional context in comments.

4 Comments

What if I wanted to search for multiple keywords? Meaning that my ip will be an array of keywords to be matched to a sentence. Btw, I don't understand about the function(fs, matched){ return '\\'+fs;}); Could you explain it further? Thanks.
I've tried your code and the result is the same as what @Crazysheep has posted. I have explain about the problem at the comment under his answer.
@imationyj I have added comments in the code, hope it explains what the lines do. Have a look at developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… to know what parameters the anonymous function accepts.
Thanks! It works perfectly! and thanks for the explanation on \b too! Totally saves my day. :D
0

You have to escape the special characters

for (var y = 0; y < $scope.length; y++) {
  var specialRegexChars = ["*", "+", ".", "(", ")", "{", "}"];

  // For each character in the word, prepend it with \ if it's in our list of special characters
  var chars = $scope.keywordsArray[y].split("");
  for (var i = 0; i < chars.length; i++) {
    if (specialRegexChars.indexOf(chars[i]) !== -1) {
      chars[i] = "\\" + chars[i];
    }
  }
  $scope.pattern += "(?=.*?\\b" + chars.join("") + "\\b)";
}

Something like that. Note that this solution is pretty verbose, and that list of special chars is very limited.

2 Comments

The result for the keyword of "c++" is /(?=.*?\bc\+\+\b).*/i right? It return false after I perform the .test("c++") function.
Seems like it won't work when I add a \b at the back of the pattern when matching "c++". If I removed it then it can return true when matching "c++" with "c++ programming book", but it won't get the result I wanted i.e.: returns true only if keyword is "programming" when search through "c++ programming book" NOT return true when the keyword is "program" or "programmin" instead

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.