简体   繁体   中英

JavaScript regexp select only last occurrence

Select only last occurrence

I'm trying to select last word (until space), those are come after last white space and @ character.

Following is my string

hello hi @why helo @blow but @name             // capture: name
hello hi @why helo @blow but name@name         // capture: blow

and another string

@blow but not know how to resolve this         // capture: blow

Here last occurrence is a first word blow , select only @ after word (obviously whitespace is not in first word).

I tryed this: https://regex101.com/r/pG1kU1/1

Simplest answer:

/\B@[^@]\w*(?!.*?\s@)/

See DEMO

You can simply use negative lookahead:

@[^@]\w*(?!.*@[^@]\w*)

regex101 demo .

(?:) means that the regex inside it cannot occur after that point. So this regex states that after the matched item, you cannot find another @-thing next to it. That means it is the last @ -thing evidently.

Note that for the case:

@blow but not know how to resolve this@
^                                     ^
|                                     |
will match this one                   |
        because this is not a valid @/

the @blow is selected, because the @ - according to your regex needs at least one character. If you want to match the @ part, you need to modify this to:

@[^@]?\w*(?!.*@[^@]?\w*)

or more efficient

@[^@]?\w*(?!.*@)

If the @ must be preceeded by the begin of the string, or whitespace, you can use a word boundary \\B :

\B@[^@]?\w*(?!.*\B@[^@]?\w*)

regex101 demo

/(?:^|\s)(@[^@]\w*)(?!.*\s@)/

should work; your word will be the 1st capture. In a language that supports lookbehinds, you could do

/(?<=^|\s)@[^@]\w*(?!.*\s@)/

and have the whole capture be what you seek; however that is not possible in JavaScript.

If you are satisfied with a mere word break and not necessarily a space, this works as well:

/\b@[^@]\w*(?!.*\s@)/

The idea is to check with positive lookahead that no further @word is after our match.

(?:^| )@([^@\s]+)(?!.*?\s@\w+.*$)

You can try this.See demo.

https://regex101.com/r/pG1kU1/3

As an alternative, how about something like this?

 var strings = [ 'hello hi @why helo @blow but @name', 'hello hi @why helo @blow but name@name', ' hello hi @why helo @blow but name@name ', '@blow but not know how to resolve this', ' @blow but not know how to resolve this', 'tada', ' ', '' ]; var wanted = strings.map(function (element) { var found = 'not found'; element.split(/\\s+/).reverse().some(function (part) { if (part.charAt(0) === '@') { found = part.slice(1); return true; } }); return found; }); document.getElementById('out').textContent = wanted.join('\\n') 
 <pre id='out'></pre> 

No complex RegExp, easy to understand and change behaviour. does require ES5 or shims but no biggy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM