how to convert substrings to quoted phrases with regex in JS script with modified boolean OR in bookmarklet?

Viewed 36

I created a JS bookmarklet that prompts for a string that can be used on LinkedIn free people search (https://www.linkedin.com/search/results/people/). That website's Keywords field used to handle standard Boolean OR strings like

Keyword1 OR Keyword2 OR "keyword phrase3" OR "keyword phrase4" OR keyword5 OR keyword6

But it no longer supports standard boolean ORs beyond 5 terms. However, LinkedIn can handle long strings if the syntax is changed to:

Keyword1 OR(Keyword2) OR("keyword phrase3") OR("keyword phrase4") OR(keyword5) OR(keyword6)

So this script (syntax formatted like a bookmarklet because it's for non-technical end users who will be prompted for input) needs to:

  • accept inputs like the very first string above (which may or may not include the ORs but we can assume they're needed if missing) and return output like second string above, and

  • auto-insert the modified Boolean OR( syntax in the right places (i.e., only before the first term in a quoted multiword phrase if the user enters something like Keyword1 Keyword2 "keyword phrase3" "keyword phrase4" keyword5 keyword6

All I have working at the moment is converting single-term (non-quoted) inputs into proper syntax with regex & replace:

javascript:(function (){ var rgxstart, s, t;if(window.getSelection){s=window.getSelection();}else{s=document.selection.createRange().text;}t=prompt('This will run a LinkedIn free search for whatever terms appear here (optional to edit field contents before pressing Enter key):',s);if(t){t = t.trim(); rgxstart = /\b\s/gm; t = t.replace(rgxstart, ") OR("); t = t+')'; void(location='https://www.linkedin.com/search/results/people/?keywords='+escape(t)+'');}else{void(s);}  })();

I found this regex on StackOverflow to select only phrases (including the quotation marks)

(["'])(?:(?=(\\?))\2.)*?\1

which works fine on a tester like Regex101.com, but when I add that to the script like this:

javascript:(function (){ var rgxstart, s, t;if(window.getSelection){s=window.getSelection();}else{s=document.selection.createRange().text;}t=prompt('This will run a LinkedIn free search for whatever terms appear here (optional to edit field contents before pressing Enter key):',s);if(t){t = t.trim(); rgxphrase = /(["'])(?:(?=(\\?))\2.)*?\1/gm; t = t.replace(rgxphrase, ") OR("); t = t+')'; void(location='https://www.linkedin.com/search/results/people/?keywords='+escape(t)+'');}else{void(s);}  })();

It generates unwanted results: e.g., it takes input of

react "full stack" node.js "back end" developer 

and

returns react ) OR( node.js ) OR( developer)

I realize it needs some kind of fancy regex lookarounds to detect if an upcoming term is not the first term within parentheses are needed, in order to know whether to insert an end-parentheses before the next word boundary, but this is way beyond my RegEx skillset.

How do I get script criteria #1 and 2 functioning?

1 Answers

You could use this regular expression to match quoted strings and unquoted words

".*?"|\S+

You could use this as an argument to match:

.match(/".*?"|\S+/g)

Be aware that if you use this as part of a script that is encoded inside an HTML attribute, like href="...", you'll need to encode those quotation marks:

.match(/".*?"|\S+/g)

To accommodate that the user might enter some "or" already, those can be removed at the start of the process with .replace(/ or /gi, ' ').

Here is the proposed script in a readable way (without encoding):

var t = prompt('This will run a LinkedIn free search for whatever terms appear here (optional to edit field contents before pressing Enter key):',
               getSelection ? getSelection() : document.selection.createRange().text);
if (t) 
    location = 'https://www.linkedin.com/search/results/people/?keywords='
       + encodeURIComponent(
            t.replace(/ or /gi, ' ')
             .trim()
             .match(/".*?"|\S+/g)
             .map(function (w, i) { return i ? 'OR('+w+')' : w })
             .join(' ')
         );

In encoded form, with the anonymous function wrapper, ready to be put in an HTML attribute:

javascript:void(function(){var t=prompt('This will run a LinkedIn free search for whatever terms appear here (optional to edit field contents before pressing Enter key):',getSelection?getSelection():document.selection.createRange().text);if(t)location='https://www.linkedin.com/search/results/people/?keywords='+encodeURIComponent(t.replace(/ or /gi, ' ').trim().match(/".*?"|\S+/g).map(function(w, i){return i?'OR('+w+')':w}).join(' '))}());

Here is a snippet that uses this code to display the URL that would be navigated to:

var t = prompt('This will run a LinkedIn free search for whatever terms appear here (optional to edit field contents before pressing Enter key):',
               getSelection ? getSelection() : document.selection.createRange().text);
if (t) 
    loc.textContent = 'https://www.linkedin.com/search/results/people/?keywords='
       + encodeURIComponent(
            t.replace(/ or /gi, ' ')
             .trim()
             .match(/".*?"|\S+/g)
             .map(function (w, i) { return i ? 'OR('+w+')' : w })
             .join(' ')
         );
<div id="loc"></div>

Related