I need to search an array in JavaScript. The search would be for only part of the string to match as the string would have additional components. I would then need to return the successfully matched array element with the full string.
Example:
const windowArray = [ "item", "thing", "id-3-text", "class" ];
I need to search for the array element with "id-" in it and I need to pull the rest of the text in the element as well (i.e. "id-3-text").
How do I do that?
If you're able to use Underscore.js in your project, the _.filter() array function makes this a snap:
// find all strings in array containing 'thi'
var matches = _.filter(
[ 'item 1', 'thing', 'id-3-text', 'class' ],
function( s ) { return s.indexOf( 'thi' ) !== -1; }
);
The iterator function can do whatever you want as long as it returns true for matches. Works great.
Update 2017-12-03:
This is a pretty outdated answer now. Maybe not the most performant option in a large batch, but it can be written a lot more tersely and use native ES6 Array/String methods like .filter() and .includes() now:
// find all strings in array containing 'thi'
const items = ['item 1', 'thing', 'id-3-text', 'class'];
const matches = items.filter(s => s.includes('thi'));
Note: There's no <= IE11 support for String.prototype.includes() (Edge works, mind you), but you're fine with a polyfill, or just fall back to indexOf().
People here are making this waaay too difficult. Just do the following...
myArray.findIndex(element => element.includes("substring"))
findIndex() is an ES6 higher order method that iterates through the elements of an array and returns the index of the first element that matches some criteria (provided as a function). In this case I used ES6 syntax to declare the higher order function. element is the parameter of the function (which could be any name) and the fat arrow declares what follows as an anonymous function (which does not need to be wrapped in curly braces unless it takes up more than one line).
Within findIndex() I used the very simple includes() method to check if the current element includes the substring that you want.
The simplest way to get the substrings array from the given array is to use filter and includes:
myArray.filter(element => element.includes("substring"));
The above one will return an array of substrings.
myArray.find(element => element.includes("substring"));
The above one will return the first result element from the array.
myArray.findIndex(element => element.includes("substring"));
The above one will return the index of the first result element from the array.
In your specific case, you can do it just with a boring old counter:
var index, value, result;
for (index = 0; index < windowArray.length; ++index) {
value = windowArray[index];
if (value.substring(0, 3) === "id-") {
// You've found it, the full text is in `value`.
// So you might grab it and break the loop, although
// really what you do having found it depends on
// what you need.
result = value;
break;
}
}
// Use `result` here, it will be `undefined` if not found
But if your array is sparse, you can do it more efficiently with a properly-designed for..in loop:
var key, value, result;
for (key in windowArray) {
if (windowArray.hasOwnProperty(key) && !isNaN(parseInt(key, 10))) {
value = windowArray[key];
if (value.substring(0, 3) === "id-") {
// You've found it, the full text is in `value`.
// So you might grab it and break the loop, although
// really what you do having found it depends on
// what you need.
result = value;
break;
}
}
}
// Use `result` here, it will be `undefined` if not found
Beware naive for..in loops that don't have the hasOwnProperty and !isNaN(parseInt(key, 10)) checks; here's why.
Off-topic:
Another way to write
var windowArray = new Array ("item","thing","id-3-text","class");
is
var windowArray = ["item","thing","id-3-text","class"];
...which is less typing for you, and perhaps (this bit is subjective) a bit more easily read. The two statements have exactly the same result: A new array with those contents.
Just search for the string in plain old indexOf
arr.forEach(function(a){
if (typeof(a) == 'string' && a.indexOf('curl')>-1) {
console.log(a);
}
});
The simplest vanilla javascript code to achieve this is
var windowArray = ["item", "thing", "id-3-text", "class", "3-id-text"];
var textToFind = "id-";
//if you only want to match id- as prefix
var matches = windowArray.filter(function(windowValue){
if(windowValue) {
return (windowValue.substring(0, textToFind.length) === textToFind);
}
}); //["id-3-text"]
//if you want to match id- string exists at any position
var matches = windowArray.filter(function(windowValue){
if(windowValue) {
return windowValue.indexOf(textToFind) >= 0;
}
}); //["id-3-text", "3-id-text"]
For a fascinating examination of some of the alternatives and their efficiency, see John Resig's recent posts:
JavaScript Trie Performance Analysis
Revised JavaScript Dictionary Search
(The problem discussed there is slightly different, with the haystack elements being prefixes of the needle and not the other way around, but most solutions are easy to adapt.)
let url = item.product_image_urls.filter(arr=>arr.match("homepage")!==null)
Filter array with string match. It is easy and one line code.
ref:
In javascript, how do you search an array for a substring match
The solution given here is generic unlike the solution 4556343#4556343, which requires a previous parse to identify a string with which to join(), that is not a component of any of the array strings.
Also, in that code /!id-[^!]*/ is more correctly, /![^!]*id-[^!]*/ to suit the question parameters:
"search an array ..." (of strings or numbers and not functions, arrays, objects, etc.)
"for only part of the string to match " (match can be anywhere)
"return the ... matched ... element" (singular, not ALL, as in "... the ... elementS")
"with the full string" (include the quotes)
... NetScape / FireFox solutions (see below for a JSON solution):
javascript: /* "one-liner" statement solution */
alert(
["x'!x'\"id-2",'\' "id-1 "', "item","thing","id-3-text","class" ] .
toSource() . match( new RegExp(
'[^\\\\]("([^"]|\\\\")*' + 'id-' + '([^"]|\\\\")*[^\\\\]")' ) ) [1]
);
or
javascript:
ID = 'id-' ;
QS = '([^"]|\\\\")*' ; /* only strings with escaped double quotes */
RE = '[^\\\\]("' +QS+ ID +QS+ '[^\\\\]")' ;/* escaper of escaper of escaper */
RE = new RegExp( RE ) ;
RA = ["x'!x'\"id-2",'\' "id-1 "', "item","thing","id-3-text","class" ] ;
alert(RA.toSource().match(RE)[1]) ;
displays "x'!x'\"id-2".
Perhaps raiding the array to find ALL matches is 'cleaner'.
/* literally (? backslash star escape quotes it!) not true, it has this one v */
javascript: /* purely functional - it has no ... =! */
RA = ["x'!x'\"id-2",'\' "id-1 "', "item","thing","id-3-text","class" ] ;
function findInRA(ra,id){
ra.unshift(void 0) ; /* cheat the [" */
return ra . toSource() . match( new RegExp(
'[^\\\\]"' + '([^"]|\\\\")*' + id + '([^"]|\\\\")*' + '[^\\\\]"' ,
'g' ) ) ;
}
alert( findInRA( RA, 'id-' ) . join('\n\n') ) ;
displays:
"x'!x'\"id-2"
"' \"id-1 \""
"id-3-text"
Using, JSON.stringify():
javascript: /* needs prefix cleaning */
RA = ["x'!x'\"id-2",'\' "id-1 "', "item","thing","id-3-text","class" ] ;
function findInRA(ra,id){
return JSON.stringify( ra ) . match( new RegExp(
'[^\\\\]"([^"]|\\\\")*' + id + '([^"]|\\\\")*[^\\\\]"' ,
'g' ) ) ;
}
alert( findInRA( RA, 'id-' ) . join('\n\n') ) ;
displays:
["x'!x'\"id-2"
,"' \"id-1 \""
,"id-3-text"
wrinkles:
The "unescaped" global RegExp is /[^\]"([^"]|\")*id-([^"]|\")*[^\]"/g with the \ to be found literally. In order for ([^"]|\")* to match strings with all "'s escaped as \", the \ itself must be escaped as ([^"]|\\")*. When this is referenced as a string to be concatenated with id-, each \ must again be escaped, hence ([^"]|\\\\")*!
A search ID that has a \, *, ", ..., must also be escaped via .toSource() or JSON or ... .
null search results should return '' (or "" as in an EMPTY string which contains NO "!) or [] (for all search).
If the search results are to be incorporated into the program code for further processing, then eval() is necessary, like eval('['+findInRA(RA,ID).join(',')+']').
--------------------------------------------------------------------------------
Digression:
Raids and escapes? Is this code conflicted?
The semiotics, syntax and semantics of /* it has no ... =! */ emphatically elucidates the escaping of quoted literals conflict.
Does "no =" mean:
"no '=' sign" as in javascript:alert('\x3D') (Not! Run it and see that there is!),
"no javascript statement with the assignment operator",
"no equal" as in "nothing identical in any other code" (previous code solutions demonstrate there are functional equivalents),
...
Quoting on another level can also be done with the immediate mode javascript protocol URI's below. (// commentaries end on a new line (aka nl, ctrl-J, LineFeed, ASCII decimal 10, octal 12, hex A) which requires quoting since inserting a nl, by pressing the Return key, invokes the URI.)
javascript:/* a comment */ alert('visible') ;
javascript:// a comment ; alert( 'not' ) this is all comment %0A;
javascript:// a comment %0A alert('visible but %\0A is wrong ') // X %0A
javascript:// a comment %0A alert('visible but %'+'0A is a pain to type') ;
Note: Cut and paste any of the javascript: lines as an immediate mode URI (at least, at most?, in FireFox) to use first javascript: as a URI scheme or protocol and the rest as JS labels.
I've created a simple to use library (ss-search) which is designed to handle objects, but could also work in your case:
search(windowArray.map(x => ({ key: x }), ["key"], "SEARCH_TEXT").map(x => x.key)
The advantage of using this search function is that it will normalize the text before executing the search to return more accurate results.
Another possibility is
var res = /!id-[^!]*/.exec("!"+windowArray.join("!"));
return res && res[0].substr(1);
that IMO may make sense if you can have a special char delimiter (here i used "!"), the array is constant or mostly constant (so the join can be computed once or rarely) and the full string isn't much longer than the prefix searched for.
I think this may help you. I had a similar issue. If your array looks like this:
var array = ["page1","1973","Jimmy"];
You can do a simple "for" loop to return the instance in the array when you get a match.
var c;
for (i = 0; i < array.length; i++) {
if (array[i].indexOf("page") > -1){
c = i;}
}
We create an empty variable, c to host our answer.
We then loop through the array to find where the array object (e.g. "page1") matches our indexOf("page"). In this case, it's 0 (the first result)
Happy to expand if you need further support.
Use this function for search substring Item.
function checkItem(arrayItem, searchItem) {
return arrayItem.findIndex(element => element.includes(searchItem)) >= 0
}
function getItem(arrayItem, getItem) {
return arrayItem.filter(element => element.includes(getItem))
}
var arrayItem = ["item","thing","id-3-text","class"];
console.log(checkItem(arrayItem, "id-"))
console.log(checkItem(arrayItem, "vivek"))
console.log(getItem(arrayItem, "id-"))
Here's your expected snippet which gives you the array of all the matched values:
var windowArray = new Array ("item","thing","id-3-text","class");
var result = [];
windowArray.forEach(val => {
if(val && val.includes('id-')) {
result.push(val);
}
});
console.log(result);
this worked for me .
const filterData = this.state.data2.filter(item=>((item.name.includes(text)) || (item.surname.includes(text)) || (item.email.includes(text)) || (item.userId === Number(text))) ) ;
Related
I want to validate following text using regular expressions
integer(1..any)/'fs' or 'sf'/ + or - /integer(1..any)/(h) or (m) or (d)
samples :
1) 8fs+60h
2) 10sf-30m
3) 2fs+3h
3) 15sf-20m
i tried with this
function checkRegx(str,id){
var arr = strSplit(str);
var regx_FS =/\wFS\w|\d{0,9}\d[hmd]/gi;
for (var i in arr){
var str_ = arr[i];
console.log(str_);
var is_ok = str_.match(regx_FS);
var err_pos = str_.search(regx_FS);
if(is_ok){
console.log(' ID from ok ' + id);
$('#'+id).text('Format Error');
break;
}else{
console.log(' ID from fail ' + id);
$('#'+id).text('');
}
}
}
but it is not working
please can any one help me to make this correct
This should do it:
/^[1-9]\d*(?:fs|sf)[-+][1-9]\d*[hmd]$/i
You were close, but you seem to be missing some basic regex comprehension.
First of all, the ^ and $ just make sure you're matching the entire string. Otherwise any junk before or after will count as valid.
The formation [1-9]\d* allows for any integer from 1 upwards (and any number of digits long).
(?:fs|sf) is an alternation (the ?: is to make the group non-capturing) to allow for both options.
[-+] and [hmd] are character classes allowing to match any one of the characters in there.
That final i allows the letters to be lowercase or uppercase.
I don't see how the expression you tried relates anyhow to the description you gave us. What you want is
/\d+(fs|sf)[+-]\d+[hmd]/
Since you seem to know a bit about regular expressions I won't give a step-by-step explanation :-)
If you need exclude zero from the "integer" matches, use [1-9]\d* instead. Not sure whether by "(1..any)" you meant the number of digits or the number itself.
Looking on the code, you
should not use for in enumerations on arrays
will need string start and end anchors to check whether _str exactly matches the regex (instead of only some part)
don't need the global flag on the regex
rather might use the RegExp test method than match - you don't need a result string but only whether it did match or not
are not using the err_pos variable anywhere, and it hardly will work with search
function checkRegx(str, id) {
var arr = strSplit(str);
var regx_FS = /^\d+(fs|sf)[+-]\d+[hmd]$/i;
for (var i=0; i<arr.length; i++) {
var str = arr[i];
console.log(str);
if (regx_FS.test(str) {
console.log(' ID from ok ' + id);
$('#'+id).text('Format Error');
break;
} else {
console.log(' ID from fail ' + id);
$('#'+id).text('');
}
}
}
Btw, it would be better to separate the validation (regex, array split, iteration) from the output (id, jQuery, logs) into two functions.
Try something like this:
/^\d+(?:fs|sf)[-+]\d+[hmd]$/i
I want to extract the store/brand names out of the url or some title string.
so the url could be something like
"http://www.store1.com/brand1-Transform-Ultra-Prepaid-/"
and title could be " brand1 Transform Ultra Prepaid Phone "
I will keep the possible store names in an array like
var store_array = ['store1', 'brand1', 'brand2']
lets say if i search the above url or title, i should get the store1 and brand1 as a result.
how to do this in jquery, am beginner, please explain me in detail.
my initial idea is that i should below, but not sure. please help.
$.each( store_array, function(index, value) {
//what to do here
});
You can do:
var url = 'http://www.store1.com/brand1-Transform-Ultra-Prepaid-/',
path = url.split('/');
var store_array = path[path.length-2].split('-');
Demo: http://jsfiddle.net/jcGsp/
This all depends on how dynamic you want it to be, another options would be a regexp:
var url = 'http://www.store1.com/brand1-Transform-Ultra-Prepaid-/';
var store_array = url.replace(/http:\/\/www.store1.com\/([^\/]+)\//,'$1').split('-');
Demo: http://jsfiddle.net/fSpr3/
you can use the split function:
let's say the url is:
url=window.location.href;
url.split('http://www.store1.com/');
title=url[1];
if the word needed from "brand1-Transform-Ultra-Prepaid-" is "brand1" then split this again with:
title.split('-');
fixed_title=title[0];
I would define a function to do the matching, and run it on the strings I am interested in
function findMatches( str ){
return store_array.filter( function( el ){
return new RegExp( "\b"+el+"\b", "i" ).test( str );
});
}
var results1 = findMatches( 'http://www.store1.com/' );
var results2 = findMatches( " brand1 Transform Ultra Prepaid Phone " );
//etc
The \b ensures 'store1' etc are complete words (so, 'store1' wouldn't match 'megastore1') and the /i makes it case insensitive.
array.filter runs a function on every member of an array and returns a copy of the array with only those members for whose the function returns true. Note that array.filter is IE9 and above (you didn't specify the platform), for other browsers there is anice polyfill here https://gist.github.com/1031656
The findMatches function goes through all the strings in the list, turns them into regular expressions, and checks whether it is found in the string. If you have a lot of test string, it may be more efficient to run indexof
function findMatches( str ){
return store_array.filter( function( el ){
return ( "-1" !== str.indexOf( el ) );
});
}
Either will work. Note that this is not using jQuery, just plain JS (albeit ECMA5)
I'm trying to do a URL GET variable replace, however the regular expression for checking whether the variable exists in amongst other GET variables is returning true when I am expecting it to return false.
The pattern I am using is: &sort=.*&
Test URL: http://localhost/search?location=any&sort=asc
Am I right to believe that this pattern should be returning false on the basis that their is no ampersand character following the sort parameter's value?
Full code:
var sort = getOptionValue($(this).attr('id'));
var url = document.URL;
if(url.indexOf('?') == -1) {
url = url+'?sort='+sort;
} else {
if(url.search('/&sort=.*&/i')) {
url.replace('/&sort=.*&/i','&sort='+sort+'&');
}
else if(url.search('/&sort=.*/i')) {
url.replace('/&sort=.*/i','&sort='+sort);
}
}
Am I right to believe that this pattern should be returning false on the basis that their is no ampersand character following the sort parameter's value?
Well, you are using String.search, which, according to the linked documentation:
If successful, search returns the index of the regular expression inside the string. Otherwise, it returns -1.
So it will return -1, or 0 or greater when there is a match. So you should test for -1, not truthiness.
Also, there is no need to pass the regexes as strings, you might as well use:
url.replace(/&sort=.*&/i,'&sort='+sort+'&');
Further, keep in mind that replace will create a new string, not replace in the string (strings in Javascript are immutable).
Finally, I don't see the need for searching for the string, and then replacing it -- it seems that you always want to replace &sort=SOMETHING with &sort=SOMETHING_ELSE, so just do that:
if(url.indexOf('?') == -1) {
url = url+'?sort='+sort;
} else {
url = url.replace(/&sort=[^&]*/i, '&sort=' + sort);
}
The javascript string function search() returns -1 if not found, not false. Your code should read:
if(url.search('/&sort=.*&/i') != -1) {
url.replace('/&sort=.*&/i','&sort='+sort+'&');
}
else if(url.search('/&sort=.*/i') != -1) {
url.replace('/&sort=.*/i','&sort='+sort);
}
You should check
if(url.search('/&sort=.*&/i') >= 0)
then it should work
You could use this code
var url = 'http://localhost/search?location=any&sort=asc';
var vars = {};
var parts = url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
});
console.log(vars);
//vars is an object with two properties: location and sort
This can be done by using
url.replace(/([?&])(sort=)([^&?]*)/, "$1$2" + sort);
The match broken down
Group 1 matches for ? or &
Group 2 matches sort=
Group 3 matches anything that is not a & or ?
Then "$1$2" + sort will replace all 3 group matches with the first 2 + your variable
examples using string "REPLACE" instead of your sort variable
url = "http://localhost/search?location=any&sort=asc&a=z"
url.replace(/([?&])(sort=)([^&?]*)/, "$1$2" + "REPLACE");
// => "http://localhost/search?location=any&sort=REPLACE&a=z"
url = "http://localhost/search?location=any&sort=asc"
url.replace(/([?&])(sort=)([^&?]*)/, "$1$2" + "REPLACE");
// => "http://localhost/search?location=any&sort=REPLACE"
url = "http://localhost/search?sort=asc"
url.replace(/([?&])(sort=)([^&?]*)/, "$1$2" + "REPLACE");
// => "http://localhost/search?sort=REPLACE"
url = "http://localhost/search?sort=asc&z=y"
url.replace(/([?&])(sort=)([^&?]*)/, "$1$2" + "REPLACE");
// => "http://localhost/search?sort=REPLACE&z=y"
The pattern I am using is: &sort=.*& Test URL:
http://localhost/search?location=any&sort=asc
Am I right to believe that this pattern should be returning false on
the basis that their is no ampersand character following the sort
parameter's value?
you are assuming right. But in your code you have else if(url.search('/&sort=.*/i')) which will match and thus still replace the value.
You should also note that your code would turn http://localhost/search?sort=asc&location=any&some=more into http://localhost/search?sort=asc&some=more. that's because because .* is greedy (trying to match as much as possible). You can avoid that by telling it to match as little as possible by appending a ? like so .*?.
That said, I believe you may be better off with a library that knows how URLs actually work. You're not compensating for parameter position, possible escaped values etc. I suggest you have a look at URI.js and replace your wicked regex with
var uri = URI(document.URL),
data = uri.query(true);
data.foo = 'bazbaz';
uri.query(data);
First a quick definition :)
Template - A string which may contain placeholders (example:"hello [name]")
Placeholder - A substring whitin square brackets (example: "name" in "hello [name]:).
Properties map - A valid object with strings as values
I need to write a code that replace placeholders (along with brackets) with the matching values in the properties map.
example:
for the following properties map:
{
"name":"world",
"my":"beautiful",
"a":"[b]",
"b":"c",
"c":"my"
}
Expected results:
"hello name" -> "hello name"
"hello [name]" -> "hello world"
"[b]" -> "c"
"[a]" -> "c" (because [a]->[b]->[c])
"[[b]]" -> "my" (because [[b]]->[c]->my)
"hello [my] [name]" -> "hello beautiful world"
var map = {
"name":"world",
"my":"beautiful",
"a":"[b]",
"b":"c",
"c":"my"
};
var str = "hello [my] [name] [[b]]";
do {
var strBeforeReplace = str;
for (var k in map) {
if (!map.hasOwnProperty(k)) continue;
var needle = "[" + k + "]";
str = str.replace(needle, map[k]);
}
var strChanged = str !== strBeforeReplace;
} while (strChanged);
document.write(str); //hello beautiful world my
The answer by #chris is excellent, I just want to provide an alternative solution using regular expressions that works "the other way round", i.e., not by looking for occurrences of the "placeholder versions" of all items in the properties map, but by repeatedly looking for occurrences of the placeholder itself, and substituting it with the corresponding value from the property map. This has two advantages:
If the property map grows very large, this solution should have
better performance (still to be benchmarked though).
The placeholder and the way substitutions work can easily be modified by adjusting the regular expression and the substitution function (might not be an issue here).
The downside is, of course, that the code is a little more complex (partly due to the fact that JavaScript lacks a nice way of substituting regular expression matches using custom functions, so that's what substituteRegExp is for):
function substituteRegExp(string, regexp, f) {
// substitute all matches of regexp in string with the value
// returned by f given a match and the corresponding group values
var found;
var lastIndex = 0;
var result = "";
while (found = regexp.exec(string)) {
var subst = f.apply(this, found);
result += string.slice(lastIndex, found.index) + subst;
lastIndex = found.index + found[0].length;
}
result += string.slice(lastIndex);
return result;
}
function templateReplace(string, values) {
// repeatedly substitute [key] placeholders in string by values[key]
var placeholder = /\[([a-zA-Z0-9]+)\]/g;
while (true) {
var newString = substituteRegExp(string, placeholder, function(match, key) {
return values[key];
});
if (newString == string)
break;
string = newString;
}
return string;
}
alert(templateReplace("hello [[b]] [my] [name]", {
"name":"world",
"my":"beautiful",
"a":"[b]",
"b":"c",
"c":"my"
})); // -> "hello my beautiful world"
Update: I did some little profiling to compare the two solutions (jsFiddle at http://jsfiddle.net/n8Fyv/1/, I also used Firebug). While #chris' solution is faster for small strings (no need for parsing the regular expression etc), this solution performs a lot better for large strings (in the order of thousands of characters). I did not compare for different sizes of the property map, but expect even bigger differences there.
In theory, this solution has runtime O(k n) where k is the depth of nesting of placeholders and n is the length of the string (assuming dictionary/hash lookups need constant time), while #chris' solution is O(k n m) where m is the number of items in the property map. All of this is only relevant for large inputs, of course.
If you're familiar with .NET's String.Format, then you should take a look at this JavaScript implementation. It supports number formatting too, just like String.Format.
Here's an example of how to use it:
var result = String.Format("Hello {my} {name}", map);
However, it would require some modification to do recursive templates.
The replace function returns the new string with the replaces, but if there weren't any words to replace, then the original string is returned. Is there a way to know whether it actually replaced anything apart from comparing the result with the original string?
A simple option is to check for matches before you replace:
var regex = /i/g;
var newStr = str;
var replaced = str.search(regex) >= 0;
if(replaced){
newStr = newStr.replace(regex, '!');
}
If you don't want that either, you can abuse the replace callback to achieve that in a single pass:
var replaced = false;
var newStr = str.replace(/i/g, function(token){replaced = true; return '!';});
As a workaround you can implement your own callback function that will set a flag and do the replacement. The replacement argument of replace can accept functions.
Comparing the before and after strings is the easiest way to check if it did anything, there's no intrinsic support in String.replace().
[contrived example of how '==' might fail deleted because it was wrong]
Javascript replace is defected by design. Why? It has no compatibility with string replacement in callback.
For example:
"ab".replace(/(a)(b)/, "$1$2")
> "ab"
We want to verify that replace is done in single pass. I was imagine something like:
"ab".replace(/(a)(b)/, "$1$2", function replacing() { console.log('ok'); })
> "ab"
Real variant:
"ab".replace(/(a)(b)/, function replacing() {
console.log('ok');
return "$1$2";
})
> ok
> "$1$2"
But function replacing is designed to receive $0, $1, $2, offset, string and we have to fight with replacement "$1$2". The solution is:
"ab".replace(/(a)(b)/, function replacing() {
console.log('ok');
// arguments are $0, $1, ..., offset, string
return Array.from(arguments).slice(1, -2)
.reduce(function (pattern, match, index) {
// '$1' from strings like '$11 $12' shouldn't be replaced.
return pattern.replace(
new RegExp("\\$" + (index + 1) + "(?=[^\\d]|$)", "g"),
match
);
}, "$1$2");
});
> ok
> "ab"
This solution is not perfect. String replacement itself has its own WATs. For example:
"a".replace(/(a)/, "$01")
> "a"
"a".replace(/(a)/, "$001")
> "$001"
If you want to care about compatibility you have to read spec and implement all its craziness.
If your replace has a different length from the searched text, you can check the length of the string before and after. I know, this is a partial response, valid only on a subset of the problem.
OR
You can do a search. If the search is successfull you do a replace on the substring starting with the found index and then recompose the string. This could be slower because you are generating 3 strings instead of 2.
var test = "Hellllo";
var index = test.search(/ll/);
if (index >= 0) {
test = test.substr(0, index - 1) + test.substr(index).replace(/ll/g, "tt");
}
alert(test);
While this will require multiple operations, using .test() may suffice:
const regex = /foo/;
const yourString = 'foo bar';
if (regex.test(yourString)) {
console.log('yourString contains regex');
// Go ahead and do whatever else you'd like.
}
The test() method executes a search for a match between a regular expression and a specified string. Returns true or false.
With indexOf you can check wether a string contains another string.
Seems like you might want to use that.
have a look at string.match() or string.search()
After doing any RegExp method, read RegExp.lastMatch property:
/^$/.test(''); //Clear RegExp.lastMatch first, Its value will be ''
'abcd'.replace(/bc/,'12');
if(RegExp.lastMatch !== '')
console.log('has been replaced');
else
console.log('not replaced');