find the pattern and dynamically build regex to match the string - javascript

If asterisk * is present in the pattern, then it means a sequence of the same character of length 3 unless it is followed by {N} which represents how many characters should appear in the sequence where N will be at least 1. My goal is to determine if the second string exactly matches the pattern of the first string in the input. I'm having trouble building the Regex pattern
*{2}* mmRRR should return TRUE
*{2}* mRRR should return FALSE
https://jsfiddle.net/82smw9zx/
sample code::
pattern1 = /'queryStrSubStr.charAt(0){patternCount}'/;
var patternMatch = new RegExp(pattern1);
if(queryStrSubStr.match(patternMatch)) {
result = true;
} else result = false;

You need to use new RegExp() to construct your regex pattern with variables (rather than attempting to include a variable directly in your regular expression literal).
You are trying to include variables queryStrSubStr.charAt(0) and patternCount in a regular expression literal like: /'queryStrSubStr.charAt(0){patternCount}'/, but JavaScript does not interpret those strings as variables inside the literal.
Following example demonstrates how to construct your regex pattern with variables as well as incorporating the html input from your fiddle so that you can test various patterns. Code comments explain how the code works.
$('.btn').click(() => {
const result = wildcards($('.enter_pattern').val());
console.log(result);
});
const wildcards = (s) => {
if (s.startsWith('*')) { // if input string starts with *
let pattern;
let [count, text] = s.split(' '); // split input string into count and text
count = count.match(/\{\d+\}/); // match count pattern like {n}
if (count) { // if there is a count
pattern = new RegExp(text.charAt(0) + count); // regex: first character + matched count pattern
} else { // if there is no count
pattern = new RegExp(text.charAt(0) + '{3}'); // regex: first character + default pattern {3}
}
return !!s.match(pattern); // return true if text matches pattern or false if not
} else { // if input string does not start with *
return 'No pattern';
}
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="enter_pattern" />
<button type="submit" class="btn">Click</button>
/*
Example test output:
Input: *{2}* mmRRR
Log: true
Input: *{2}* mRRR
Log: false
Input: * mmmRRR
Log: true
Input: * mmRRR
Log: false
Input: mmRRR
Log: No pattern
*/

First you need to calulate the pattern using a regex:
/\*\{(\d+)\}\*/
It matches a star, a left Square bracket, followed by one or more digits and ending with a right Square bracket and a star.
How to use:
var text = 'mmRRR';
var char = text.charAt(0);
var pattern = '*{2}*';
var counter = /\*\{(\d+)\}\*/.exec(pattern)[1] || '3';
var regex = new RegeExp('^' + char + '\{' + counter + '}$');
var result = text.match(regex);

Related

How can i check for only one occurence only of each provided symbol?

I have a provided array of symbols, which can be different. For instance, like this - ['#']. One occurrence of each symbol is a mandatory. But in a string there can be only one of each provided sign.
Now I do like this:
const regex = new RegExp(`^\\w+[${validatedSymbols.join()}]\\w+$`);
But it also returns an error on signs like '=' and so on. For example:
/^\w+[#]\w+$/.test('string#=string') // false
So, the result I expect:
'string#string' - ok
'string##string - not ok
Using a complex regex is most likely not the best solution. I think you would be better of creating a validation function.
In this function you can find all occurrence of the provided symbols in string. Then return false if no occurrences are found, or if the list of occurrences contains duplicate entries.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
function validate(string, symbols) {
if (symbols.length == 0) {
throw new Error("at least one symbol must be provided in the symbols array");
}
const symbolRegex = new RegExp(symbols.map(escapeRegExp).join("|"), "g");
const symbolsInString = string.match(symbolRegex); // <- null if no match
// string must at least contain 1 occurrence of any symbol
if (!symbolsInString) return false;
// symbols may only occur once
const hasDuplicateSymbols = symbolsInString.length != new Set(symbolsInString).size;
return !hasDuplicateSymbols;
}
const validatedSymbols = ["#", "="];
const strings = [
"string!*string", // invalid (doesn't have "#" nor "=")
"string#!string", // valid
"string#=string", // valid
"string##string", // invalid (max 1 occurance per symbol)
];
console.log("validatedSymbols", "=", JSON.stringify(validatedSymbols));
for (const string of strings) {
const isValid = validate(string, validatedSymbols);
console.log(JSON.stringify(string), "//=>", isValid);
}
I think you are looking for the following:
const regex = new RegExp(`^\\w+[${validatedSymbols.join()}]?\\w+$`);
The question mark means 1 or 0 of the previous group.
You might also need to escape the symbols in validatedSymbols as some symbols have a different meaning in regex
Edit:
For mandatory symbols it would be easier to add a group per symbol:
^\w+(#\w*){1}(#\w*){1}\w+$
Where the group is:
(#\w*){1}

Group array with two words, rather than one

CODE BELOW: When a word has been written, it stores that as its own array, meaning every single word is its own array, and then later checked for reoccurrences.
What i want: Instead of it creating an array of a word (after spacebar has been hit), i want it to do it after 2 words have been written.
IE: Instead of me writing "Hello" + spacebar, and the code creating "hello" as an array. I'd like it to wait until i've written "hello my" + spacebar and then create an array with those two numbers.
I am guessing this has something to do with the regular expression?
I've tried many different things (a little bit of a newbie) and i cannot understand how to get it to group 2 words together rather than one.
const count = (text) => {
const wordRegex = new RegExp(`([\\p{Alphabetic}\]+)`, 'gu');
let result;
const words = {};
while ((result = wordRegex.exec(text)) !== null) {
const word = result[0].toLowerCase();
if (!words[word]) {
words[word] = [];
}
words[word].push(result.index);
words[word].push(result.index + word.length);
}
return words;
};
You may use
const wordRegex = /\p{Alphabetic}+(?:\s+\p{Alphabetic}+)?/gu;
Details
\p{Alphabetic}+ - 1+ alphabetic chars
(?:\s+\p{Alphabetic}+)? - an optional sequence of:
\s+ - 1+ whitespaces
\p{Alphabetic}+ - 1+ alphabetic chars
The second word is matched optionally so that the final odd word could be matched, too.
See the JS demo below:
const count = (text) => {
const wordRegex = /\p{Alphabetic}+(?:\s+\p{Alphabetic}+)?/gu;
let result;
const words = {};
while ((result = wordRegex.exec(text)) !== null) {
const word = result[0].toLowerCase();
if (!words[word]) {
words[word] = [];
}
words[word].push(result.index);
words[word].push(result.index + word.length);
}
return words;
};
console.log(count("abc def ghi"))
A RegExp constructor way of defining this regex is
const wordRegex = new RegExp("\\p{Alphabetic}+(?:\\s+\\p{Alphabetic}+)?", "gu");
However, since the pattern is static, no variables are used to build the pattern, you can use the regex literal notation as shown at the top of the answer.

Return unique digits of a time format string using regex

Need to create a regex pattern that will return unique digits before or after a : symbol, using String.match. It should only return the digit, not the : symbol. PS: I know there is other (maybe easier) ways to do this, but I want to use regex for learning purposes
let s;
let regex = /(^\d:)(:\d$)/g // I tried this, off course it didn't work
s = '12:34'
s.match(regex) // return null
s = '1:34'
s.match(regex) // return [1]
s = '12:4'
s.match(regex) // return [4]
s = '1:4'
s.match(regex) // return [1,4]
Try using this:
let regex = /(((?<=:)\d(?!\d))|((?<!\d)\d(?=:)))/g
This will match the patterns you want!
Here's a reference for Regex.
let s;
let regex = /(((?<=:)\d(?!\d))|((?<!\d)\d(?=:)))/g
s = '12:34'
console.log(s.match(regex)) // return null
s = '1:34'
console.log(s.match(regex)) // return [1]
s = '12:4'
console.log(s.match(regex)) // return [4]
s = '1:4'
console.log(s.match(regex)) // return [1,4]
Example done in JavaScript. The 2nd regex is the most simple, it matches a digit followed by a colon, followed by a digit (you could use this with the g flag if there is more than one occurrence in your text).
1st regex matches the entire string and MAY have one or more characters before the 1st digit and one or more characters after the 2nd one. This will only capture one occurrence for the entire string.
let regex1 = /^.*(\d):(\d).*$/;
let regex2 = /(\d):(\d)/;
console.log("Make sure the entire string only contains one instance");
['12:34', '1:34', '12:4', '1:4' ].forEach( (s) => console.log(s.match(regex1) ));
console.log("Match the first instance found");
['12:34', '1:34', '12:4', '1:4' ].forEach( (s) => console.log(s.match(regex2) ));
Not sure what do you mean by "unique".
But if you want to just get numbers then you can use + or * quantifiers.
/^(\d+):(\d+)$/

What's the JS RegExp for this specific string?

I have a rather isolated situation in an inventory management program where our shelf locations have a specific format, which is always Letter: Number-Letter-Number, such as Y: 1-E-4. Most of us coworkers just type in "y1e4" and are done with it, but that obviously creates issues with inconsistent formats in a database. Are JS RegExp's the ideal way to automatically detect and format these alphanumeric strings? I'm slowly wrapping my head around JavaScript's Perl syntax, but what's a simple example of formatting one of these strings?
spec: detect string format of either "W: D-W-D" or "WDWD" and return "W: D-W-D"
This function will accept any format and return undefined if it doesnt match, returns the formatted string if a match does occur.
function validateInventoryCode(input) {
var regexp = /^([a-zA-Z]+)(?:\:\s*)?(\d+)-?(\w+)-?(\d+)$/
var r = regexp.exec(input);
if(r != null) {
return `${r[1]}: ${r[2]}-${r[3]}-${r[4]}`;
}
}
var possibles = ["y1e1", "y:1e1", "Y: 1r3", "y: 32e4", "1:e3e"];
possibles.forEach(function(posssiblity) {
console.log(`input(${posssiblity}), result(${validateInventoryCode(posssiblity)})`);
})
function validateInventoryCode(input) {
var regexp = /^([a-zA-Z]+)(?:\:\s*)?(\d+)-?(\w+)-?(\d+)$/
var r = regexp.exec(input);
if (r != null) {
return `${r[1]}: ${r[2]}-${r[3]}-${r[4]}`;
}
}
I understand the question as "convert LetterNumberLetterNumber to Letter: Number-Letter-Number.
You may use
/^([a-z])(\d+)([a-z])(\d+)$/i
and replace with $1: $2-$3-$4
Details:
^ - start of string
([a-z]) - Group 1 (referenced with $1 from the replacement pattern) capturing any ASCII letter (as /i makes the pattern case-insensitive)
(\d+) - Group 2 capturing 1 or more digits
([a-z]) - Group 3, a letter
(\d+) - Group 4, a number (1 or more digits)
$ - end of string.
See the regex demo.
var re = /^([a-z])(\d+)([a-z])(\d+)$/i;
var s = 'y1e2';
var result = s.replace(re, '$1: $2-$3-$4');
console.log(result);
OR - if the letters must be turned to upper case:
var re = /^([a-z])(\d+)([a-z])(\d+)$/i;
var s = 'y1e2';
var result = s.replace(re,
(m,g1,g2,g3,g4)=>`${g1.toUpperCase()}: ${g2}-${g3.toUpperCase()}-${g4}`
);
console.log(result);
this is the function to match and replace the pattern: DEMO
function findAndFormat(text){
var splittedText=text.split(' ');
for(var i=0, textLength=splittedText.length; i<textLength; i++){
var analyzed=splittedText[i].match(/[A-z]{1}\d{1}[A-z]{1}\d{1}$/);
if(analyzed){
var formattedString=analyzed[0][0].toUpperCase()+': '+analyzed[0][1]+'-'+analyzed[0][2].toUpperCase()+'-'+analyzed[0][3];
text=text.replace(splittedText[i],formattedString);
}
}
return text;
}
i think it's just as it reads:
y1e4
Letter, number, letter, number:
/([A-z][0-9][A-z][0-9])/g
And yes, it's ok to use regex in this case, like form validations and stuff like that. it's just there are some cases on which abusing of regular expressions gives you a bad performance (into intensive data processing and the like)
Example
"HelloY1E4world".replace(/([A-z][0-9][A-z][0-9])/g, ' ');
should return: "Hello world"
regxr.com always comes in handy

How to match with javascript and regex?

I have the following HTML:
<span id="UnitCost5">$3,079.95 to $3,479.95</span>
And i want to use Javascript and Regex to get all number matches.
So i want my script function to return: 3,079.95 AND 3,479.95
Note the text may be different so i need the solution as generic as posible, may be it will be like this:
<span id="UnitCost5">$3,079.95 And Price $3,479.95</span>
All the numbers would be matched by:
\.?\d[\d.,]*
This assumes the numbers you look for can start with a decimal dot. If they cannot, this would work (and maybe produce less false positives):
\d[\d.,]*
Be aware that different local customs exist in number formatting.
I assume that you use appropriate means to get hold of the text value of the HTML nodes you wish to process, and that HTML parsing is not part of the excercise.
You don't want to capture all numbers, otherwise you would get the 5 in the id, too. I would guess, what you're looking for is numbers looking like this: $#,###.##
Here goes the expression for that:
/\$[0-9]{1,3}(,[0-9]{3})*(\.[0-9]+)?/
\$ The dollar sign
[0-9]{1,3} One to three digits
(,[0-9]{3})* [Optional]: Digit triplets, preceded by a comma
(\.[0-9]+)? [Optional]: Even more digits, preceded by a period
/(?:\d{1,3},)*\d{1,3}(?:\.\d+)?/g;
Let's break that into parts for explanations:
(?:\d{1,3},)* - Match any numbers separated by a thousand-divider
\d{1,3} - Match the numbers before the decimal point
(?:.\d+) - Match an arbitrary number of decimals
Flag 'g' - Make a global search to find all matches in the string
You can use it like this:
var regex = /(?:\d{1,3},)*\d{1,3}(?:\.\d+)?/g;
var numbers = "$3,079.95 And Price $3,479.95".match(regex);
// numbers[0] = 3,079.95
// numbers[1] = 3,479.95
A very simple solution is the following one. Note that it will also match some invalid number strings like $..44,.777.
\$[0-9,.]+
(function () {
var reg = /\$([\d\.,]+)\s[\w\W]+\s\$([\d\.,]+)$/;
// this function used to clean inner html
function trim(str) {
var str = str.replace(/^\s\s*/, ''),
ws = /\s/,
i = str.length;
while (ws.test(str.charAt(--i)));
return str.slice(0, i + 1);
}
function getNumbersFromElement(elementId) {
var el = document.getElementById(elementId),
text = trim(el.innerHTML),
firstPrice,
secondPrice,
result;
result = reg.exec(text);
if (result[1] && result[2]) {
// inside this block we have valid prices
firstPrice = result[1];
secondPrice = result[2];
// do whatever you need
return firstPrice + ' AND ' + secondPrice;
} else {
return null; // otherwise
}
}
// usage:
getNumbersFromElement('UnitCost5');
})();
The following will return an array of all prices found in the string
function getPrices(str) {
var reg = /\$([\d,.]+)/g;
var prices =[];
var price;
while((price = reg.exec(str))!=null) {
prices.push(price);
}
return prices;
}
edit: note that the regex itself may return some false positives

Categories

Resources