1

I need a regular expression in javascript that will get a string with a specific substring from a list of space delimited strings.

For example, I have;

  • widget util cookie i18n-username

I want to be able to return only i18n-username.

How

ClaraU
  • 877
  • 3
  • 11
  • 22

4 Answers4

3

You could use the following function, using a regex to match for your string surrounded by either a space or the beginning or end of a line. But you'll have to be careful about preparing any regular expression special characters if you plan to use them, since the search argument will be interpreted as a string instead of a RegExp literal:

var hasClass = function(s, klass) {
  var r = new RegExp("(?:^| )(" + klass + ")(?: |$)")
    , m = (""+s).match(r);
  return (m) ? m[1] : null;
};

hasClass("a b c", "a"); // => "a"
hasClass("a b c", "b"); // => "b"
hasClass("a b c", "x"); // => null

var klasses = "widget util cookie i18n-username";
hasClass(klasses, "username"); // => null
hasClass(klasses, "i18n-username"); // => "i18n-username"
hasClass(klasses, "i18n-\\w+"); // => "i18n-username"

As others have pointed out, you could also simply use a "split" and "indexOf":

var hasClass = function(s, klass) {
  return (""+s).split(" ").indexOf(klass) >= 0;
};

However, note that the "indexOf" function was introduced to JavaScript somewhat recently, so for older browsers you might have to implement it yourself.

var hasClass = function(s, klass) {
  var a=(""+s).split(" "), len=a.length, i;
  for (i=0; i<len; i++) {
    if (a[i] == klass) return true;
  }
  return false;
};

[Edit]

Note that the split/indexOf solution is likely faster for most browsers (though not all). This jsPerf benchmark shows which solution is faster for various browsers - notably, Chrome must have a really good regular expression engine!

maerics
  • 151,642
  • 46
  • 269
  • 291
  • My preference for finding classnames with a regexp is /\bclassname\b/ – HBP Jun 01 '11 at 08:42
  • Thanks maerics, i need to check for strings beginning with i18n-* and return that string, rather than a true/false dependent on whether it exists or not. is a regular expression more efficient in this scenario then or should i go the indexof route instead? – ClaraU Jun 01 '11 at 09:31
  • @Hans B PUFAL: that was my first idea but it doesn't quite work because CSS classes may contain hyphens, so a solution using regex word boundaries would erroneously match substrings like "i18n" and "username". – maerics Jun 01 '11 at 14:57
  • @clara cruz: it's hard to tell which is more efficient in this scenario, but [this jsPerf demo](http://jsperf.com/regex-vs-string-indexof-for-css-classes) shows that (to my surprise) the regex solution is faster in some browsers. – maerics Jun 01 '11 at 15:03
1
function getString(subString, string){
    return (string.match(new RegExp("\S*" + subString + "\S*")) || [null])[0];
}

To Use:

var str = "widget util cookie i18n-username";
getString("user", str);  //returns i18n-username
Jonathon
  • 2,571
  • 5
  • 28
  • 49
  • The only thing you have to worry about is if subString contains any special regex characters. – Jonathon Jun 01 '11 at 01:51
  • 1
    Your regex function should be `RegExp` not `RegEx`. – Eli Jun 01 '11 at 03:34
  • 1
    Your function fails is the substring is not found since the match returns null in that case. This returns null in that case : return (string.match(new RegExp("\S*" + subString + "\S*")) || [null])[0]; – HBP Jun 01 '11 at 04:43
0

Does this need to be a regex? Would knowing if the string existed be sufficient? Regular expressions are inefficient (slower) and should be avoided if possible:

var settings = 'widget util cookie i18n-username',
    // using an array in case searching the string is insufficient
    features = settings.split(' ');

if (features.indexOf('i18n-username') !== -1) {
     // do something based on having this feature
}

If whitespace wouldn't cause an issue in searching for a value, you could just search the string directly:

var settings = 'widget util cookie i18n-username';

if (settings.indexOf('i18n-username') !== -1) {
    // do something based on having this value
}

It then becomes easy to make this into a reusable function:

(function() {
    var App = {},
        features = 'widget util cookie i18n-username';

    App.hasFeature = function(feature) {
        return features.indexOf(feature) !== -1;
        // or if you prefer the array:
        return features.split(' ').indexOf(feature) !== -1;
    };

    window.App = App;
})();

// Here's how you can use it:
App.hasFeature('i18n-username'); // returns true

EDIT

You now say you need to return all strings that start with another string, and it is possible to do this with a regular expression as well, although I am unsure about how efficient it is:

(function() {
    var App = {},
        features = 'widget util cookie i18n-username'.split(' ');

    // This contains an array of all features starting with 'i18n'
    App.i18nFeatures = features.map(function(value) {
        return value.indexOf('i18n') === 0;
    });

    window.App = App;
})();
Eli
  • 17,397
  • 4
  • 36
  • 49
  • I've been under the impression that regular expressions were more efficient, i guess i have perhaps been misinformed. are there scenarios where regular expression could be more efficient? also, i need to check for strings beginning with i18n-* should have made that clear. is a regular expression more efficient in this scenario then? – ClaraU Jun 01 '11 at 09:28
-1

/i18n-\w+/ ought to work. If your string has any cases like other substrings can start with i18n- or your user names have chars that don't fit the class [a-zA-Z0-9_], you'll need to specify that.

var str = "widget util cookie i18n-username";
alert(str.match(/i18n-\w+/));


Edit: If you need to match more than one string, you can add on the global flag (/g) and loop through the matches.
var str = "widget i18n-util cookie i18n-username";
var matches = str.match(/i18n-\w+/g);

if (matches) {
    for (var i = 0; i < matches.length; i++)
        alert(matches[i]);
}
else
    alert("phooey, no matches");
Chris
  • 4,393
  • 1
  • 27
  • 33
  • I think you mean the class `[-a-zA-Z0-9_]`. But ove4rall since ti is whitespace delimited there is no real reason not to just use the `\S` class. – Jonathon Jun 01 '11 at 01:57
  • Also overly specific, he did not say find the strong that starts with "i18n-" but find a specific substring so something like `/\S*substring\S*/` would of been more appropriate. – Jonathon Jun 01 '11 at 01:59
  • 1
    Well, he did say "I want to be able to return only i18n-username." I interpreted that as taking the class that has the user's name prefixed with i18n. The question isn't very specific, so that may be the incorrect interpretation. Also, `\w` matches `[A-Za-z0-9_]`. https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/regexp – Chris Jun 01 '11 at 02:28
  • Thanks Rfvgyhn, i need to check for strings beginning with i18n-* and return that string, what is ur take on the efficiency of regular expressions, is it more efficient to split and loop. somehow i'm stuck on the idea that regular expressions are supposed to be better, need a little help understanding this. thank u – ClaraU Jun 01 '11 at 09:34
  • If you need to match more than one, a regular expression is a good match (har har) for this problem. See my edit for an example. – Chris Jun 01 '11 at 15:38