I am trying to replace a string with two sets of patterns. For example,
var pattern1 = '12345abcde/'; -> this is dynamic.
var myString = '12345abcde/hd123/godaddy_item'
my end goal is to get the value between two slashes which is hd123
I have
var stringIneed = myString.replace(pattern1, '').replace('godaddy_item','');
The above codes work but I think there is more elegant solution. Can anyone help me out on this? Thanks a lot!
UPDATE:
To be more clear, the pattern is per environement string. For example,
pattern1 could be something like:
https://myproject-development/item on development environment.
and
https://myproject/item on Production
myString could usually be like
https://myproject/item/hd123/godaddy_item
or
https://myproject-development/item/hd123/godaddy_item
and I need to get 'hd123' in my case.
I'd strongly suggest not using regular expressions for this, especially when simple String and Array methods will easily suffice and be far more understandable, such as:
// your question shows you can anticipate the sections you
// don't require, so put both/all of those portions into an
// array:
var unwanted = ['12345abcde', 'godaddy_item'],
// the string you wish to find the segment from:
myString = '12345abcde/hd123/godaddy_item',
// splitting the String into an array by splitting on the '/'
// characters, filtering that array using an arrow function
// in which the section is the current array-element of the
// array over which we're iterating; and here we keep those
// sections which are not found in the unwanted Array (the index
// an element not found in an Array is returned as -1):
desired = myString.split('/').filter(section => unwanted.indexOf(section) === -1);
console.log(desired); // ["hd123"]
Avoiding Arrow functions, for browsers not supporting ES6 (and having removed the code comments):
var unwanted = ['12345abcde', 'godaddy_item'],
myString = '12345abcde/hd123/godaddy_item',
desired = myString.split('/').filter(function (section) {
return unwanted.indexOf(section) === -1;
});
console.log(desired); // ["hd123"]
Or:
// the string to start with and filter:
var myString = '12345abcde/hd123/godaddy_item',
// splitting the string by the '/' characters and keeping those whose
// index is greater than 0 (so 'not the first') and also less than the
// length of the array-1 (since JS arrays are zero-indexed while length
// is 1-based):
wanted = myString.split('/').filter((section, index, array) => index > 0 && index < array.length - 1);
console.log(wanted); // ["hd123"]
JS Fiddle demo
If, however, the requisite string to be found is always the penultimate portion of the supplied string, then we can use Array.prototype.filter() to return only that portion:
var myString = '12345abcde/hd123/godaddy_item',
wanted = myString.split('/').filter((section, index, array) => index === array.length - 2);
console.log(wanted); // ["hd123"]
JS Fiddle demo.
References:
Array.prototype.filter().
Arrow functions.
String.prototype.split().
You can use
.*\/([^\/]+)\/.*$
Regex Demo
JS Demo
var re = /.*\/([^\/]+)\/.*$/g;
var str = '12345abcde/hd123/godaddy_item';
while ((m = re.exec(str)) !== null) {
document.writeln("<pre>" + m[1] + "</br>" + "</pre>");
}
You can easily do something like this:
myString.split('/').slice(-2)[0]
This will return the item directly, in simple most way.
var myString = 'https://myproject/item/hd123/godaddy_item';
console.log(myString.split('/').slice(-2)[0]); // hd123
myString = 'https://myproject-development/item/hd123/godaddy_item';
console.log(myString.split('/').slice(-2)[0]); // hd123
Try using match() as shown below:
var re = /\/(.*)\//;
var str = '12345abcde/hd123/godaddy_item';
var result = str.match(re);
alert(result[1]);
To say that David's answer will "easily suffice and be far more understandable" is a matter of opinion - this regex option (which includes building up the expression from variables) really couldn't be much simpler:
var pathPrefix = '12345abcde/'; //dynamic
var pathToTest = '12345abcde/hd123/godaddy_item';
var pattern = new RegExp(pathPrefix + '(.*?)\/')
var match = pattern.exec(pathToTest);
var result = (match != null && match[1] != null ? '[' + match[1] + ']' : 'no match was found.'); //[hd123]
Related
I am looking to remove any value after ':->' in JavaScript
For example if 'Packet:->3', I would like to store "Packet:->" in the variable so I can use it before the if statement seen below. Pretty much I am looking to remove any digits after '>'
I was trying the below, but did not have much luck.
NTEremoved = NTE.indexOf(':->');
What would be the best way of doing this?
if(NTE == 'Packet:->' || NTE == 'Serving:->' || NTE == 'Can/Carton/Bottle:->'){
}
String split.
const testStr1 = "Packet:->3";
const testStr2 = "BlahBlahBlah278:->Hello hello this is cool";
const result1 = testStr1.split(":->")[0] + ":->"; // split "splits" the string into an array based on the delimiter ":->"; the second part would be 3
const result2 = testStr2.split(":->")[0] + ":->";
console.log(result1);
console.log(result2);
Docs.
I would do something like this, to take care also of edge cases (assuming you don't care about what is coming after the first :->:
let texts = ["Packet:->11", "Cat:->22", "Packet:->:->:->44"];
for (let text of texts) {
console.log(text.replace(/(:->).*$/, "$1"))
}
Since you have mentioned you have tries to use indexOf before but fail to do that, I will provide you a way using a combination of indexOf and String.slice
let string = "Serving:->3"
//Indexof return the first index of an element so you have to add 3 (the length of ":->"
let newstring = string.slice(0,string.indexOf(":->")+3)
console.log(newstring)
Suppose I have a sting like this: ABC5DEF/G or it might be ABC5DEF-15 or even just ABC5DEF, it could be shorter AB7F, or AB7FG/H.
I need to create a javascript variable that contains the substring only up to the '/' or the '-'. I would really like to use an array of values to break at. I thought maybe to try something like this.
...
var srcMark = array( '/', '-' );
var whereAt = new RegExp(srcMark.join('|')).test.str;
alert("whereAt= "+whereAt);
...
But this returns an error: ReferenceError: Can't find variable: array
I suspect I'm defining my array incorrectly but trying a number of other things I've been no more successful.
What am I doing wrong?
Arrays aren't defined like that in JavaScript, the easiest way to define it would be with:
var srcMark = ['/','-'];
Additionally, test is a function so it must be called as such:
whereAt = new RegExp(srcMark.join('|')).test(str);
Note that test won't actually tell you where, as your variable suggests, it will return true or false. If you want to find where the character is, use String.prototype.search:
str.search(new RegExp(srcMark.join('|'));
Hope that helps.
You need to use the split method:
var srcMark = Array.join(['-','/'],'|'); // "-|/" or
var regEx = new RegExp(srcMark,'g'); // /-|\//g
var substring = "222-22".split(regEx)[0] // "222"
"ABC5DEF/G".split(regEx)[0] // "ABC5DEF"
From whatever i could understand from your question, using this RegExp /[/-]/ in split() function will work.
EDIT:
For splitting the string at all special characters you can use new RegExp(/[^a-zA-Z0-9]/) in split() function.
var arr = "ABC5DEF/G";
var ans = arr.split(/[/-]/);
console.log(ans[0]);
arr = "ABC5DEF-15";
ans = arr.split(/[/-]/);
console.log(ans[0]);
// For all special characters
arr = "AB7FG/H";
ans = arr.split(new RegExp(/[^a-zA-Z0-9]/));
console.log(ans[0]);
You can use regex with String.split.
It will look something like that:
var result = ['ABC5DEF/G',
'ABC5DEF-15',
'ABC5DEF',
'AB7F',
'AB7FG/H'
].map((item) => item.split(/\W+/));
console.log(result);
That will create an Array with all the parts of the string, so each item[0] will contain the text till the / or - or nothing.
If you want the position of the special character (non-alpha-numeric) you can use a Regular Expression that matches any character that is not a word character from the basic Latin alphabet. Equivalent to [^A-Za-z0-9_], that is: \W
var pattern = /\W/;
var text = 'ABC5DEF/G';
var match = pattern.exec(text);
var position = match.index;
console.log('character: ', match[0]);
console.log('position: ', position);
I've two variables:
var input = "user1#gmail.com";
var preferredPatterns = ["*#gmail.com", "*#yahoo.com", "*#live.com"];
Want to match the input with preferred pattern array. If any of the patterns matches I've to do certain task (in this example, input is a definite match). How can I match against an array of pattern in javascript?
You can compile your patterns (if they are valid regular expressions) into one for performance:
var masterPattern = new RegExp(patterns.join('|'));
Putting it all together:
var input = 'user1#gmail.com';
var preferredPatterns = [
".*#gmail.com$",
".*#yahoo.com$",
".*#live.com$"
];
var masterPattern = new RegExp(preferredPatterns.join('|'));
console.log(masterPattern.test(input));
// true
You need to use RegExp constructor while passing a variable as regex.
var input = 'user1#gmail.com';
var preferredPatterns = [".*#gmail\\.com$", ".*#yahoo\\.com$", ".*#live\\.com$"];
for (i=0; i < preferredPatterns.length;i++) {
if(input.match(RegExp(preferredPatterns[i]))) {
console.log(preferredPatterns[i])
}
}
Dot is a special meta-character in regex which matches any character. You need to escape the dot in the regex to match a literal dot.
As #zerkms said, you could use the below list of patterns also.
var preferredPatterns = ["#gmail\\.com$", "#yahoo\\.com$", "#live\\.com$"];
Try this helper function:
/**
* Returns an integer representing the number of items in the patterns
* array that contain the target string text
*/
function check(str, patterns) {
return patterns.reduce(function (previous, current) {
return previous + (str.indexOf(current) == -1 ? 0 : 1);
}, 0);
}
check("user#gmail.com", ["#gmail.com", "#yahoo.com", "#live.com"]; // returns 1
check("user#live.com", ["#gmail.com", "#yahoo.com", "#live.com"]; // returns 0
If you want a general approach to matching against a list of regular expressions then some version of Avinash Raj's answer will work.
Based on the fact that you are specifying certain domains, you might want to match any valid email address using the regex here, and if it matches then check if the domain is a preferred one. There are a number of different ways you could do that of course. Here's just a simple example, splitting on the # and using jQuery.inArray() to check if the domain is preferred.
var preferredDomains = ["gmail.com", "yahoo.com", "live.com"];
function isValid(inputVal) {
var re = /^([\w-]+(?:\.[\w-]+)*)#((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
return re.test(inputVal) && $.inArray(inputVal.split('#')[1], preferredDomains) > -1;
}
The advantage here is that the underlying regex doesn't change, just the much easier to read/maintain list of domains. You could tweak this to capture the domain in a group, instead of using split().
No regexp you may do as follows;
function matchPattern(xs, [y,...ys]){
function helper([x,...xs]){
return "*" + xs.join('') === y ? true
: xs.length ? helper(xs)
: false;
}
return helper(xs) ? y
: ys.length ? matchPattern(xs,ys)
: "No Match..!";
}
var input = "user1#gmail.com",
preferredPatterns = ["*#yahoo.com", "*#live.com", "*#gmail.com"];
result = matchPattern(input, preferredPatterns);
console.log(result);
preferredPatterns.forEach(function(element, index){
if(input.match('/'+element) != null){
console.log('matching ' + element)
}
})
you can write your custom logic if a string matches any pattern.
You may iterate through array and then use regex to compare with individual items.
Let's say I have a URL:
http://something.com/somethingheretoo
and I want to get what's after the 3rd instance of /?
something like the equivalent of indexOf() which lets me input which instance of the backslash I want.
If you know it starts with http:// or https://, just skip past that part with this one-liner:
var content = aURL.substring(aURL.indexOf('/', 8));
This gives you more flexibility if there are multiple slashes in that segment you want.
let s = 'http://something.com/somethingheretoo';
parts = s.split('/');
parts.splice(0, 2);
return parts.join('/');
Try something like the following function, which will return the index of the nth occurrence of the search string s, or -1 if there are n-1 or fewer matches.
String.prototype.nthIndexOf = function(s, n) {
var i = -1;
while(n-- > 0 && -1 != (i = this.indexOf(s, i+1)));
return i;
}
var str = "some string to test";
alert(str.nthIndexOf("t", 3)); // 15
alert(str.nthIndexOf("t", 7)); // -1
alert(str.nthIndexOf("z", 4)); // -1
var sub = str.substr(str.nthIndexOf("t",3)); // "test"
Of course if you don't want to add the function to String.prototype you can have it as a stand-alone function by adding another parameter to pass in the string you want to search in.
If you want to stick to indexOf:
var string = "http://something/sth1/sth2/sth3/"
var lastIndex = string.indexOf("/", lastIndex);
lastIndex = string.indexOf("/", lastIndex);
lastIndex = string.indexOf("/", lastIndex);
string = string.substr(lastIndex);
If you want to get the path of that given URL, you can also use a RE:
string = string.match(/\/\/[^\/]+\/(.+)?/)[1];
This RE searches for "//", accepts anything between "//" and the next "/", and returns an object. This object has several properties. propery [1] contains the substring after the third /.
Another approach is to use the Javascript "split" function:
var strWord = "me/you/something";
var splittedWord = strWord.split("/");
splittedWord[0] would return "me"
splittedWord[1] would return "you"
splittedWord[2] would return "something"
It sounds like you want the pathname. If you're in a browser, keep an a element handy...
var _a = document.createElement('a');
...and let it do the parsing for you.
_a.href = "http://something.com/somethingheretoo";
alert( _a.pathname.slice(1) ); // somethingheretoo
DEMO: http://jsfiddle.net/2qT9c/
In your case, you could use the lastIndexOf() method to get the 3rd forward slash.
Here's a very cool way of handling this:
How can I remove all characters up to and including the 3rd slash in a string?
My preference of the proposed solutions is
var url = "http://blablab/test/page.php";
alert(url.split("/")[3]);
//-> "test"
Inestead of using indexOf it is possible to do this this way:
const url = 'http://something.com/somethingheretoo';
const content = new URL(url).pathname.slice(1);
Is it possible to do something like this?
var pattern = /some regex segment/ + /* comment here */
/another segment/;
Or do I have to use new RegExp() syntax and concatenate a string? I'd prefer to use the literal as the code is both more self-evident and concise.
Here is how to create a regular expression without using the regular expression literal syntax. This lets you do arbitary string manipulation before it becomes a regular expression object:
var segment_part = "some bit of the regexp";
var pattern = new RegExp("some regex segment" + /*comment here */
segment_part + /* that was defined just now */
"another segment");
If you have two regular expression literals, you can in fact concatenate them using this technique:
var regex1 = /foo/g;
var regex2 = /bar/y;
var flags = (regex1.flags + regex2.flags).split("").sort().join("").replace(/(.)(?=.*\1)/g, "");
var regex3 = new RegExp(expression_one.source + expression_two.source, flags);
// regex3 is now /foobar/gy
It's just more wordy than just having expression one and two being literal strings instead of literal regular expressions.
Just randomly concatenating regular expressions objects can have some adverse side effects. Use the RegExp.source instead:
var r1 = /abc/g;
var r2 = /def/;
var r3 = new RegExp(r1.source + r2.source,
(r1.global ? 'g' : '')
+ (r1.ignoreCase ? 'i' : '') +
(r1.multiline ? 'm' : ''));
console.log(r3);
var m = 'test that abcdef and abcdef has a match?'.match(r3);
console.log(m);
// m should contain 2 matches
This will also give you the ability to retain the regular expression flags from a previous RegExp using the standard RegExp flags.
jsFiddle
I don't quite agree with the "eval" option.
var xxx = /abcd/;
var yyy = /efgh/;
var zzz = new RegExp(eval(xxx)+eval(yyy));
will give "//abcd//efgh//" which is not the intended result.
Using source like
var zzz = new RegExp(xxx.source+yyy.source);
will give "/abcdefgh/" and that is correct.
Logicaly there is no need to EVALUATE, you know your EXPRESSION. You just need its SOURCE or how it is written not necessarely its value. As for the flags, you just need to use the optional argument of RegExp.
In my situation, I do run in the issue of ^ and $ being used in several expression I am trying to concatenate together! Those expressions are grammar filters used accross the program. Now I wan't to use some of them together to handle the case of PREPOSITIONS.
I may have to "slice" the sources to remove the starting and ending ^( and/or )$ :)
Cheers, Alex.
Problem If the regexp contains back-matching groups like \1.
var r = /(a|b)\1/ // Matches aa, bb but nothing else.
var p = /(c|d)\1/ // Matches cc, dd but nothing else.
Then just contatenating the sources will not work. Indeed, the combination of the two is:
var rp = /(a|b)\1(c|d)\1/
rp.test("aadd") // Returns false
The solution:
First we count the number of matching groups in the first regex, Then for each back-matching token in the second, we increment it by the number of matching groups.
function concatenate(r1, r2) {
var count = function(r, str) {
return str.match(r).length;
}
var numberGroups = /([^\\]|^)(?=\((?!\?:))/g; // Home-made regexp to count groups.
var offset = count(numberGroups, r1.source);
var escapedMatch = /[\\](?:(\d+)|.)/g; // Home-made regexp for escaped literals, greedy on numbers.
var r2newSource = r2.source.replace(escapedMatch, function(match, number) { return number?"\\"+(number-0+offset):match; });
return new RegExp(r1.source+r2newSource,
(r1.global ? 'g' : '')
+ (r1.ignoreCase ? 'i' : '')
+ (r1.multiline ? 'm' : ''));
}
Test:
var rp = concatenate(r, p) // returns /(a|b)\1(c|d)\2/
rp.test("aadd") // Returns true
Providing that:
you know what you do in your regexp;
you have many regex pieces to form a pattern and they will use same flag;
you find it more readable to separate your small pattern chunks into an array;
you also want to be able to comment each part for next dev or yourself later;
you prefer to visually simplify your regex like /this/g rather than new RegExp('this', 'g');
it's ok for you to assemble the regex in an extra step rather than having it in one piece from the start;
Then you may like to write this way:
var regexParts =
[
/\b(\d+|null)\b/,// Some comments.
/\b(true|false)\b/,
/\b(new|getElementsBy(?:Tag|Class|)Name|arguments|getElementById|if|else|do|null|return|case|default|function|typeof|undefined|instanceof|this|document|window|while|for|switch|in|break|continue|length|var|(?:clear|set)(?:Timeout|Interval))(?=\W)/,
/(\$|jQuery)/,
/many more patterns/
],
regexString = regexParts.map(function(x){return x.source}).join('|'),
regexPattern = new RegExp(regexString, 'g');
you can then do something like:
string.replace(regexPattern, function()
{
var m = arguments,
Class = '';
switch(true)
{
// Numbers and 'null'.
case (Boolean)(m[1]):
m = m[1];
Class = 'number';
break;
// True or False.
case (Boolean)(m[2]):
m = m[2];
Class = 'bool';
break;
// True or False.
case (Boolean)(m[3]):
m = m[3];
Class = 'keyword';
break;
// $ or 'jQuery'.
case (Boolean)(m[4]):
m = m[4];
Class = 'dollar';
break;
// More cases...
}
return '<span class="' + Class + '">' + m + '</span>';
})
In my particular case (a code-mirror-like editor), it is much easier to perform one big regex, rather than a lot of replaces like following as each time I replace with a html tag to wrap an expression, the next pattern will be harder to target without affecting the html tag itself (and without the good lookbehind that is unfortunately not supported in javascript):
.replace(/(\b\d+|null\b)/g, '<span class="number">$1</span>')
.replace(/(\btrue|false\b)/g, '<span class="bool">$1</span>')
.replace(/\b(new|getElementsBy(?:Tag|Class|)Name|arguments|getElementById|if|else|do|null|return|case|default|function|typeof|undefined|instanceof|this|document|window|while|for|switch|in|break|continue|var|(?:clear|set)(?:Timeout|Interval))(?=\W)/g, '<span class="keyword">$1</span>')
.replace(/\$/g, '<span class="dollar">$</span>')
.replace(/([\[\](){}.:;,+\-?=])/g, '<span class="ponctuation">$1</span>')
It would be preferable to use the literal syntax as often as possible. It's shorter, more legible, and you do not need escape quotes or double-escape backlashes. From "Javascript Patterns", Stoyan Stefanov 2010.
But using New may be the only way to concatenate.
I would avoid eval. Its not safe.
You could do something like:
function concatRegex(...segments) {
return new RegExp(segments.join(''));
}
The segments would be strings (rather than regex literals) passed in as separate arguments.
You can concat regex source from both the literal and RegExp class:
var xxx = new RegExp(/abcd/);
var zzz = new RegExp(xxx.source + /efgh/.source);
Use the constructor with 2 params and avoid the problem with trailing '/':
var re_final = new RegExp("\\" + ".", "g"); // constructor can have 2 params!
console.log("...finally".replace(re_final, "!") + "\n" + re_final +
" works as expected..."); // !!!finally works as expected
// meanwhile
re_final = new RegExp("\\" + "." + "g"); // appends final '/'
console.log("... finally".replace(re_final, "!")); // ...finally
console.log(re_final, "does not work!"); // does not work
No, the literal way is not supported. You'll have to use RegExp.
the easier way to me would be concatenate the sources, ex.:
a = /\d+/
b = /\w+/
c = new RegExp(a.source + b.source)
the c value will result in:
/\d+\w+/
I prefer to use eval('your expression') because it does not add the /on each end/ that ='new RegExp' does.