Three conditions for reg ex? - javascript

I'm moving up from Photoshop scripts to something else:
Using JavaScript I need to check the validity of website address for three things.
A dot (.) before and after "somesite"
Nothing between ".somesite" and ".com/"
Nothing between ".com" and the "/"
In my example I'm looking at www.somesite.com
Here's the code so far:
URIArr = [
"https://www.somesite.com/find-work-home",
"www.somesite.com/",
"blahsomesite.com/bananas/stuff",
"something.somesite.com/bananas/cheese",
"blahsomesite.com/bananas/123",
"www.blah.somesite.m.com/bananas/5678",
"blah.somesite.comm/bananas/ook",
]
for (var i = 0; i < URIArr.length; i++)
{
var temp = URIArr[i];
var valid = checkURL(".somesite", temp);
if (!valid)
{
alert(temp + " is " + checkURL(".somesite", temp));
}
}
function removeTrailingSlashes(site)
{
return site.replace(/\/$/, "");
}
function checkURL(webstr, str)
{
// A dot (.) before and after "somesite"
// Nothing between ".somesite" and ".com/"
// Nothing between ".com" and the "/"
var test1 = false;
var test2 = false;
var test3 = false;
var c = ".com";
var haystack = str.toLowerCase();
var needle = webstr.toLowerCase();
haystack = removeTrailingSlashes(haystack);
if (!haystack.charAt(haystack .length) === "/")
haystack += "/";
var n = haystack.indexOf(needle);
var m = n + (needle.length);
// first check
if (str.charAt(n) && str.charAt(m) === ".") test1 = true;
//second check
var o = haystack.indexOf(c);
if (o-m === 0) test2 = true;
// third check
var p = o + (c.length);
var truncStr = haystack.substring(o, haystack.length);
var q = truncStr.indexOf("/") + o;
if (q-p === 0) test3 = true;
// final triplecheck
if ((test1 == true) && (test2 == true) && (test3== true)) return true
return false
}
The question is this:
- Did I miss any tricks (I noticed that for the third condition I had to add trailing slashes - even though they might not be present)
But more importantly:
- Could this this be reworked with (three) regular expressions?
Is this a job for Reginald X. Pression?

You can use the following single regex for all three tests:
\.somesite(?=\.com\/)
Js code:
var regex = /\.somesite(?=\.com\/)/g;
var valid = regex.test(myString); //true if found.. else false
See DEMO

Hmm I feel like your three conditions of:
A dot (.) before and after "somesite"
Nothing between ".somesite" and ".com/"
Nothing between ".com" and the "/"
can be simplify to 1 condition:
.somesite.com/
And if that is so, actually without using regex, you can solve it via:
var valid = somestring.indexOf(".somesite.com/") > -1;
using regex would be:
var valid = somestring.match(/\.somesite\.com\//);

Related

How to match two patterns with a space between them in JavaScript?

I know how to match one pattern using JavaScript:
var pattern = somePattern
if (!pattern.test(email)) { //do something }
but what if I have to match 2 patterns with a space between them so if I have this:
word1 word2
word1 should match pattern1
word2 should match pattern2
a space should be between them
How can I achieve this using JavaScript?
word1word2 is refused (even if they much pattern1 and pattern2 in order, because of the lack of space)
word1 should be an IP; word2 should be a number
Some examples:
172.30.10.10 10 (acceptable)
172.30.10.1010 (not acceptable)
10 10 (not acceptable)
10 172.30.10.10 (not acceptable)
According to the documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/source
The RegExp object has a source property, which returns a string representation of the regex.
Here's an example.
var validName = /\w+ \w+/
var validEmail = /[^# ]+#.+\..+/
var combined = new RegExp(validName.source + ' ' + validEmail.source);
console.log(combined.test('John Doe jdoe#example.com'));
// outputs true
console.log(combined.test('John Doe bademail#'));
// outputs false
However, keep in mind that this solution will NOT work if the regexes include boundary markers like $ and ^.
Combine it into a single pattern:
var pattern = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\s+\d{1,}/;
var test= '172.30.10.10 10';
var matched = test.match(pattern);
http://regex101.com/r/kU9cN3/3
UPDATE further to Brian's comment. If they need to be coded as separate patterns you can do as follows. This may be useful if you want to re-use patterns or make other combinations.
var ip = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/,
number = /\d{1,}/,
combinedRegExp = new RegExp(ip.source+' '+number.source);
var testString = '172.30.10.10 10';
var result = combinedRegExp.test(testString);
console.log(result);//true
http://jsfiddle.net/7Lrsxov8/
Building on Joe Frambach's answer, you could perform some sanity checking on the input:
function combinePatterns(pattern1, pattern2, options) {
if (pattern1.constructor != RegExp || pattern2.constructor != RegExp) {
throw '`pattern1` and `pattern2` must be RegExp objects';
}
var pattern1_str = pattern1.source;
var pattern2_str = pattern2.source;
options = options || {};
// Ensure combining the patterns makes something sensible
var p1_endOfLine, p2_startOfLine;
if (pattern1_str.lastIndexOf('$') == pattern1_str.length - 1) {
p1_endOfLine = true;
if (options.stripBadDelimiters || options.swapBadDelimiters) {
pattern1_str = pattern1_str.substr(0, pattern1_str.length - 1);
}
if (options.swapBadDelimiters
&& pattern2_str.lastIndexOf('$') != pattern2_str.length - 1) {
pattern2_str += '$';
}
}
if (pattern2_str.indexOf('^') == 0) {
p2_startOfLine = true;
if (options.stripBadDelimiters || options.swapBadDelimiters) {
pattern2_str = pattern2_str.substr(1);
}
if (options.swapBadDelimiters && pattern1_str.indexOf('^') != 0) {
pattern1_str = '^' + pattern1_str;
}
}
if (p1_endOfLine && p2_startOfLine && options.swapPatterns) {
var tmp = pattern1_str;
pattern1_str = pattern2_str;
pattern2_str = tmp;
}
return new RegExp(pattern1_str + ' ' + pattern2_str);
}
var first = combinePatterns(/abc/, /123/);
var second = combinePatterns(/abc$/, /^123/);
var third = combinePatterns(/abc$/, /^123/, { stripBadDelimiters: true });
var fourth = combinePatterns(/abc$/, /^123/, { swapBadDelimiters: true });
var fifth = combinePatterns(/abc$/, /^123/, { swapPatterns: true });
// first = /abc 123/
// second = /abc$ ^123/
// third = /abc 123/
// fourth = /^abc 123$/
// fourth = /^123 abc$/
This isn't the end-all be-all of what you can do to help ensure your input produces the desired output, but it should illustrate the sorts of possibilities that are open to you when reconstructing the regex pattern in this fashion.
A bit more compact and complete solution:
var ipNum = "\\d{1,3}";
var ip = "(" + ipNum + "\\.){3}" + ipNum;
var num = "\\d+";
var ipRE = new RegExp("^\\s*" + ip + "\\s+" + ipNum + "\\s*$");
console.log(ipRE.test(" 172.30.10.10 10 ")); // true

Replacing commas with dot and dot with commas

I am trying to replace all dots for comma and commas for dots and was wondering what is the best practice for doing this. If I do it sequentially, then the steps will overwrite each other.
For example:
1,234.56 (after replacing commas) --> 1.234.56 (after replacing dots) --> 1,234,56
Which is obviously not what I want.
One option I guess is splitting on the characters and joining afterwards using the opposite character. Is there an easier/better way to do this?
You could use a callback
"1,234.56".replace(/[.,]/g, function(x) {
return x == ',' ? '.' : ',';
});
FIDDLE
If you're going to replace more than two characters, you could create a convenience function using a map to do the replacements
function swap(str, swaps) {
var reg = new RegExp('['+Object.keys(swaps).join('')+']','g');
return str.replace(reg, function(x) { return swaps[x] });
}
var map = {
'.':',',
',':'.'
}
var result = swap("1,234.56", map); // 1.234,56
FIDDLE
You could do the following:
var str = '1,234.56';
var map = {',':'.','.':','};
str = str.replace(/[,.]/g, function(k) {
return map[k];
});
Working Demo
Do it in stages using placeholder text:
var foo = '1,234.56';
foo = foo
.replace(',', '~comma~')
.replace('.', '~dot~')
.replace('~comma~', '.')
.replace('~dot~', ',')
You could use a for loop. Something like:
var txt = document.getElementById("txt");
var newStr = "";
for (var i = 0; i < txt.innerHTML.length; i++){
var char = txt.innerHTML.charAt(i);
if (char == "."){
char = ",";
}else if (char == ","){
char = ".";
}
newStr += char;
}
txt.innerHTML = newStr;
Here's a fiddle:
http://jsfiddle.net/AyLQt/1/
Have to say though, #adenoeo's answer is way more slick :D
In javascript you can use
var value = '1.000.000,55';
var splitValue = value.split('.');
for (var i = 0; i < splitValue.length; i++) {
var valPart = splitValue[i];
var newValPart = valPart.replace(',', '.');
splitValue[i] = newValPart;
}
var newValue = splitValue.join(',');
console.log(newValue);

Want to get specific value from string

I have a JavaScript string sentrptg2c#appqueue#sentrptg2c#vwemployees#.
I want to get last string vwemployees through RegExp or from any JavaScript function.
Please suggest a way to do this in JavaScript.
You can use the split function:
var str = "sentrptg2c#appqueue#sentrptg2c#vwemployees#";
str = str.split("#");
str = str[str.length-2];
alert(str);
// Output: vwemployees
The reason for -2 is because of the trailing #. If there was no trailing #, it would be -1.
Here's a JSFiddle.
var s = "...#value#";
var re = /#([^#]+)#^/;
var answer = re.match(s)[1] || null;
if you're sure the string will be separated by "#" then you can split on # and take the last entry... I'm stripping off the last #, if it's there, before splitting the string.
var initialString = "sentrptg2c#appqueue#sentrptg2c#vwemployees#"
var parts = initialString.replace(/\#$/,"").split("#"); //this produces an array
if(parts.length > 0){
var result = parts[parts.length-1];
}
Try something like this:
String.prototype.between = function(prefix, suffix) {
s = this;
var i = s.indexOf(prefix);
if (i >= 0) {
s = s.substring(i + prefix.length);
}
else {
return '';
}
if (suffix) {
i = s.indexOf(suffix);
if (i >= 0) {
s = s.substring(0, i);
}
else {
return '';
}
}
return s;
}
No magic numbers:
var str = "sentrptg2c#appqueue#sentrptg2c#vwemployees#";
var ar = [];
ar = str.split('#');
ar.pop();
var o = ar.pop();
alert(o);
jsfiddle example

remove all empty values from url

I want to remove all empty values from an url:
var s="value1=a&value2=&value3=b&value4=c&value5=";
s = s.replace(...???...);
alert(s);
Expected output:
value1=a&value3=b&value4=c
I only need the query part of the URL to be taken into account.
Something like this:
s = s.replace(/[^=&]+=(&|$)/g,"").replace(/&$/,"");
That is, remove groups of one or more non-equals/non-ampersand characters that are followed by an equals sign and ampersand or end of string. Then remove any leftover trailing ampersand.
Demo: http://jsfiddle.net/pKHzr/
s = s.replace(/[^?=&]+=(&|$)/g,"").replace(/&$/,"");
Added a '?' to nnnnnn's answer to fix the issue where the first parameter is empty in a full URL.
This should do the trick:
var s="value1=a&value2=&value3=b&value4=c&value5=";
var tmp = s.split('&')
var newS = '';
for(var i in a) {
var t = a[i];
if(t[t.length - 1] !== '=') {
newS += t + '&';
}
}
if(newS[newS.length - 1] === '&') {
newS = newS.substr(0, newS.length - 1);
}
console.log(newS);
I don't find any solution to do that with one Regex expression.
But you could loop through your string and construct a new result string : http://jsfiddle.net/UQTY2/3/
var s="value1=a&value2=&value3=b&value4=c&value5=";
var tmpArray = s.split('&');
var final = '';
for(var i=0 ; i<tmpArray.length ; i++)
if(tmpArray[i].split('=')[1] != '')
final += tmpArray[i] + '&';
final = final.substr(0,final.length-1)
alert(final)
Where do you take all the values?
I suggest using an array:
function getValues(str){
var values = [];
var s = str.split('&');
for(var val in s){//source is a
var split = val.split('=');
if(split [1] != '' && split [1] != null){
values.push(val);
}
}
return values.join('&');
}

Javascript word-count for any given DOM element

I'm wondering if there's a way to count the words inside a div for example. Say we have a div like so:
<div id="content">
hello how are you?
</div>
Then have the JS function return an integer of 4.
Is this possible? I have done this with form elements but can't seem to do it for non-form ones.
Any ideas?
g
If you know that the DIV is only going to have text in it, you can KISS:
var count = document.getElementById('content').innerHTML.split(' ').length;
If the div can have HTML tags in it, you're going to have to traverse its children looking for text nodes:
function get_text(el) {
ret = "";
var length = el.childNodes.length;
for(var i = 0; i < length; i++) {
var node = el.childNodes[i];
if(node.nodeType != 8) {
ret += node.nodeType != 1 ? node.nodeValue : get_text(node);
}
}
return ret;
}
var words = get_text(document.getElementById('content'));
var count = words.split(' ').length;
This is the same logic that the jQuery library uses to achieve the effect of its text() function. jQuery is a pretty awesome library that in this case is not necessary. However, if you find yourself doing a lot of DOM manipulation or AJAX then you might want to check it out.
EDIT:
As noted by Gumbo in the comments, the way we are splitting the strings above would count two consecutive spaces as a word. If you expect that sort of thing (and even if you don't) it's probably best to avoid it by splitting on a regular expression instead of on a simple space character. Keeping that in mind, instead of doing the above split, you should do something like this:
var count = words.split(/\s+/).length;
The only difference being on what we're passing to the split function.
Paolo Bergantino's second solution is incorrect for empty strings or strings that begin or end with whitespaces. Here's the fix:
var count = !s ? 0 : (s.split(/^\s+$/).length === 2 ? 0 : 2 +
s.split(/\s+/).length - s.split(/^\s+/).length - s.split(/\s+$/).length);
Explanation: If the string is empty, there are zero words; If the string has only whitespaces, there are zero words; Else, count the number of whitespace groups without the ones from the beginning and the end of the string.
string_var.match(/[^\s]+/g).length
seems like it's a better method than
string_var.split(/\s+/).length
At least it won't count "word " as 2 words -- ['word'] rather than ['word', '']. And it doesn't really require any funny add-on logic.
Or just use Countable.js to do the hard job ;)
document.deepText= function(hoo){
var A= [];
if(hoo){
hoo= hoo.firstChild;
while(hoo!= null){
if(hoo.nodeType== 3){
A[A.length]= hoo.data;
}
else A= A.concat(arguments.callee(hoo));
hoo= hoo.nextSibling;
}
}
return A;
}
I'd be fairly strict about what a word is-
function countwords(hoo){
var text= document.deepText(hoo).join(' ');
return text.match(/[A-Za-z\'\-]+/g).length;
}
alert(countwords(document.body))
Or you can do this:
function CountWords (this_field, show_word_count, show_char_count) {
if (show_word_count == null) {
show_word_count = true;
}
if (show_char_count == null) {
show_char_count = false;
}
var char_count = this_field.value.length;
var fullStr = this_field.value + " ";
var initial_whitespace_rExp = /^[^A-Za-z0-9]+/gi;
var left_trimmedStr = fullStr.replace(initial_whitespace_rExp, "");
var non_alphanumerics_rExp = rExp = /[^A-Za-z0-9]+/gi;
var cleanedStr = left_trimmedStr.replace(non_alphanumerics_rExp, " ");
var splitString = cleanedStr.split(" ");
var word_count = splitString.length -1;
if (fullStr.length <2) {
word_count = 0;
}
if (word_count == 1) {
wordOrWords = " word";
} else {
wordOrWords = " words";
}
if (char_count == 1) {
charOrChars = " character";
} else {
charOrChars = " characters";
}
if (show_word_count & show_char_count) {
alert ("Word Count:\n" + " " + word_count + wordOrWords + "\n" + " " + char_count + charOrChars);
} else {
if (show_word_count) {
alert ("Word Count: " + word_count + wordOrWords);
} else {
if (show_char_count) {
alert ("Character Count: " + char_count + charOrChars);
}
}
}
return word_count;
}
The get_text function in Paolo Bergantino's answer didn't work properly for me when two child nodes have no space between them. eg <h1>heading</h1><p>paragraph</p> would be returned as headingparagraph (notice lack of space between the words). So prepending a space to the nodeValue fixes this. But it introduces a space at the front of the text but I found a word count function that trims it off (plus it uses several regexps to ensure it counts words only). Word count and edited get_text functions below:
function get_text(el) {
ret = "";
var length = el.childNodes.length;
for(var i = 0; i < length; i++) {
var node = el.childNodes[i];
if(node.nodeType != 8) {
ret += node.nodeType != 1 ? ' '+node.nodeValue : get_text(node);
}
}
return ret;
}
function wordCount(fullStr) {
if (fullStr.length == 0) {
return 0;
} else {
fullStr = fullStr.replace(/\r+/g, " ");
fullStr = fullStr.replace(/\n+/g, " ");
fullStr = fullStr.replace(/[^A-Za-z0-9 ]+/gi, "");
fullStr = fullStr.replace(/^\s+/, "");
fullStr = fullStr.replace(/\s+$/, "");
fullStr = fullStr.replace(/\s+/gi, " ");
var splitString = fullStr.split(" ");
return splitString.length;
}
}
EDIT
kennebec's word counter is really good. But the one I've found includes a number as a word which is what I needed. Still, that's easy to add to kennebec's. But kennebec's text retrieval function will have the same problem.
This should account for preceding & trailing whitespaces
const wordCount = document.querySelector('#content').innerText.trim().split(/\s+/).length;
string_var.match(/[^\s]+/g).length - 1;

Categories