fox
fox

Reputation: 16506

regex to match optional prefix

I have a string of text that will look like

 · 7:30pm · a/a · ★★ · fri sold out · Multi-day event ·

or

 · 7:30pm · a/a · ★★ · sold out · Multi-day event ·

I want to capture sold out if that text exists or fri sold out if that text exists.

My attempted regex is /^.*\s(\w*\ssold out|sold out).*$/ but that is only capturing sold out.

How do I capture either string of text?

Edit: I will not always have the · anchors on either side. I also want to be able to grab the same info from, i.e.:

10pm · 21+ · ★ · late show - sold out ·

Upvotes: 2

Views: 1622

Answers (3)

Mariano
Mariano

Reputation: 6511

You're almost there. The problem with your pattern is the first .*

By default, the regex engine is greedy, .* consumes as much as it can, and it has precedence over the rest of the pattern (it's on the left). To change this behaviour, you can use a lazy quantifier. Adding the extra "?" in .*? makes it repeat as few as possible.

/^.*?\s(\w*\ssold out|sold out).*$/

regex101 Demo


Now that we made clear what was wrong, let's see a few more things. I think \w* should require at least 1 char, so we can change the quantifier and use \w+. Also, we can make it shorter using a non-capturing group to make the \w*\s optional, thus shortening the pattern:

/^.*?\s((?:\w+\s)?sold out).*$/

And if you don't actually need to match the whole line, you can use:

/\s((?:\w+\s)?sold out)/

regex101 Demo

Upvotes: 2

T.J. Crowder
T.J. Crowder

Reputation: 1074276

You can capture an optional \w+ in front of sold out (fortunately, have that nice solid sold out to work with):

var rex = /((?:[\w]+ )?sold out)/;
var match = str.match(rex);
var text = match && match[1];

Live Example:

test("· 7:30pm · a/a · ★★ · fri sold out · Multi-day event ·");
test("· 7:30pm · a/a · ★★ · sold out · Multi-day event ·");
test("10pm · 21+ · ★ · late show - sold out ·");
function test(str) {
  var rex = /((?:[\w]+ )?sold out)/;
  var match = str.match(rex);
  var text = match && match[1];
  snippet.log("'" + str + "' =>");
  snippet.log("'" + text + "'");
}
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Here's an explanation of that regex, but basically the outer (...) is a capture group, then (?:[\w]+ )? says "optionally match one or more word characters followed by a space" (the ? after the non-capturing group (?:...) is what makes it optional), and of course sold out is our anchoring text.

Upvotes: 4

vks
vks

Reputation: 67968

★+\s*\·\s*([^·]+)(?=·)

You can use this and grab the group.See demo.

https://regex101.com/r/cJ6zQ3/1

var re = /★+\s*\·\s*([^·]+)(?=·)/g; 
var str = ' · 7:30pm · a/a · ★★ · fri sold out · Multi-day event ·\n\nor\n\n · 7:30pm · a/a · ★★ · sold out · Multi-day event ·';
var m;

while ((m = re.exec(str)) !== null) {
    if (m.index === re.lastIndex) {
        re.lastIndex++;
    }
    // View your result using the m-variable.
    // eg m[0] etc.
}

Upvotes: 1

Related Questions