How to make regular expression only accept special formula? - javascript

I'm making html page for special formula using angularJS.
<input ng-model="expression" type="text" ng-blur="checkFormula()" />
function checkFormula() {
let regex;
if (scope.formulaType === "sum") {
regex = "need sum regular expression here"; // input only like as 1, 2, 5:6, 8,9
} else {
regex = "need arithmetic regular expression here"; // input only like as 3 + 4 + 6 - 9
}
if (!regex.test(scope.expression)) {
// show notification error
Notification.error("Please input expression correctly");
return;
}
// success case
if (scope.formulaType === "sum") {
let fields = expression.split(',');
let result = fields.reduce((acc, cur) => { return acc + Number(cur) }, 0);
// processing result
} else {
// need to get fields with + and - sign.
// TODO: need coding more...
let result = 0;
// processing result
}
}
So I want to make inputbox only accept my formula.
Formulas are two cases.
1,2,3:7,9
or
4-3+1+5
First case, means sum(1,2,3,4,5,6,7,9) and second case means (4-3+1+5).
But I don't know regular expression how to process it.
I searched google, but I didn't get result for my case.
So I want to need 2 regex match.

1,2,3:7,9
Fot this pattern, you can try this one:
^\d+(?::\d+)?(?:,\d+(?::\d+)?)*$
^\d+(?::\d+)?
matches string starts with a number(e.g. 1) or two numbers separated by a column (e.g. 1:2)
(?:,\d+(?::\d+)?)*$
repeats the previous pattern with a comma in front of it as many time as possible until meets the end of the string (e.g. ,2:3,4:5,6)
4-3+1+5
Fot this pattern, you can try this one:
^\d+(?:[+-]\d+)*$
Like the previous one, this is much simpler
^\d+
starts with a number(e.g. 12)
(?:[+-]\d+)*$
repeats the previous pattern with a - or + in front of it as many time as possible until meets the end of the string (e.g. +2-3+14)
Also, if you need at least one pair of numbers.
Such as 1,2 is allowed but just 1 is not. You can just change the * before $ to +:
^\d+(?::\d+)?(?:,\d+(?::\d+)?)+$
^\d+(?:[+-]\d+)+$
And if you allow white spaces in between them:
^\d+(?:\s*:\s*\d+)?(?:\s*,\s*\d+(?:\s*:\s*\d+)?)+$
^\d+(?:\s*[+-]\s*\d+)+$

Related

.toLowerCase() / .toUpperCase() not working

I'm trying to get better at javascript through codewars.com katas, and I came across an exercice in which things like element[i]=element[i].toLowerCase() doesn't change anything at all.
I would like to have some help with my code, here is the exercice's instructions followed by my code:
(Please note that I'm not very experienced with JS so the code may not be perfect at all)
A string is considered to be in title case if each word in the string
is either:
(a) capitalised (that is, only the first letter of the word
is in upper case) or
(b) considered to be an exception and put entirely into lower case unless it is the first word, which is always capitalised.
Write a function that will convert a string into title case, given an optional list of exceptions (minor words). The list of minor words will be given as a string with each word separated by a space.
Your function should ignore the case of the minor words string -- it should behave in the same way even if the case of the minor word string is changed.
Arguments:
First argument (required): the original string to be converted.
Second argument (optional): space-delimited list of minor words that must always be lowercase except for the first word in the string. The JavaScript/CoffeeScript tests will pass undefined when this argument is unused.
function titleCase(title, minorWords) {
if(title.length==0){return ""}
var titlesplit = title.split(" ")
if(minorWords){
minorWords=minorWords.split(" ")
}
var solutionstring = ""
titlesplit.forEach(element => myfunction(element,minorWords))
solutionstring[0] = solutionstring[0].toUpperCase()
return solutionstring
function myfunction(element,minorWords){
var elementlength= element.length
var i=0
if(minorWords && minorWords.includes(element)){
for(i;i<elementlength;i++){
element[i]=element[i].toLowerCase()
}
}else {
for(i;i<elementlength;i++){
if(i==0){element[i]=element[i].toUpperCase()}
else{element[i]=element[i].toLowerCase()}
}
}
if(solutionstring.length==0){solutionstring=solutionstring+element}else{solutionstring=solutionstring+" "+element}
return
}
}
As pointed out in comments, Strings are immutable in JavaScript.
Additionally, for searching use Maps instead of includes.
Likewise you can see what Set in JavaScript is and easily use Set here.
Added comments for you better understanding.
function titleCase(title, minorWords) {
// Use === for comparison
// Prefer using curly braces even for single statements
if (title.length === 0) {
return "";
}
var titlesplit = title.split(" ");
// Maps/Objects give O(1) search compared to arrays O(n)
// Key,value pairs - similar to dictionary
var minorWordsMap = {};
minorWords.split(" ").forEach(i => minorWordsMap[i.toLowerCase()] = true);
var finalWords = titlesplit.map((element, index) => convertCase(element, index));
finalWords[0] = toPascalCase(finalWords[0]);
return finalWords.join(" ");
function toPascalCase(s) {
s = s.split("");
s[0] = s[0].toUpperCase();
return s.join("");
}
function convertCase(element, index) {
const lElement = element.toLowerCase();
// If element is part of exception words, ignore
if(index !== 0 && minorWordsMap[lElement]) {
return element;
}
// If first element or not in exception list, send Title case
return toPascalCase(lElement);
}
}

Text Input Real time JS validation as Float which accepts floating point and comma

I want to validate an input in real time way.
The input has type text and must validate only an input having : number(s) and/or floating point or comma.
Also the input accepts only two numbers after the floating point/comma.
Examples :
- 12.23 Valid
- 12,23 Valid
- 12.2 Valid
- 12,02 Valid
- 2 Valid
- 12.035 Invalid
- 12.36E Invalid
- test Invalid
I suggest tracking the live input validation with a /^(\d*)([,.]\d{0,2})?$/ regex that allows typing any 0 or more digits at the start, and then an optional substring of , or . and then 0, 1 or 2 digits. If there is a match, re-format the value by replacing , with .. If there input value is not matched, replace it with the last good value (say, introduce a variable called prevValue for that).
Once you want to submit this value, you need to make sure the value is in the final format, that is, there should be no . at the end. To enable this, add a pattern attribute to your <input> and assign the ^\d+(?:\.\d{1,2})?$ regex to it. Here, it will already require 1+ digits at the start of the string, and then will match an optional substring of a . followed with 1 or 2 digits. See the regex demo. Since the comma will get replaced with a dot, you need no [.,] pattern, \. is enough.
Also, it is a good idea to handle the input value change on paste.
var prevValue = "";
var patt = /^(\d*)([,.]\d{0,2})?$/;
function validateCurrencyPattern(price){
var matchedString = price.match(patt);
if (matchedString) {
prevValue = matchedString[1] + (matchedString[2] ? matchedString[2].replace(",", ".") : "")
return prevValue;
}
else {
return prevValue;
}
}
$(document).on("keypress keyup blur paste","#field", function (event) {
$(this).val(validateCurrencyPattern($(this).val()));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<input type="text" id="field" name="field" pattern="^\d+(?:\.\d{1,2})?$"/>
<input type="Submit"/>
</form>
Since I did not find the solution on stack and spent some hours to develop a solution that can help others i'll share what i've done :
I used the RegExp pattern to validate the number.but i can't do it with one pattern so i've created two patterns.
The first validates: x*.yy
And the second validates: x*,yy
Constraints : isNumeric doesn't accept float with comma.so that's why i've converted it.
The function validation function code :
and The call for function mixing the events (keypress keyup blur)
function validateCurrencyPattern(price){
var patt = new RegExp(/[0-9]+[.]{1}[0-9]{2}/i);
var convertedPrice =price.replace(',', '.');
var matchedString = price.match(patt) ;
var matchedString2 = convertedPrice.match(patt) ;
if (matchedString) {
return matchedString
}
if (matchedString2) {
return matchedString2
}
if((!$.isNumeric(convertedPrice))|| convertedPrice<0){
return null;
}
else if(!matchedString && !matchedString2){
return convertedPrice;
}
}
$(document).on("keypress keyup blur","#field", function (event) {
$(this).val(validateCurrencyPattern($(this).val()));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" id="field" name="field">
Feel Free to optimize this solution or suggest another alternative that may be better than the existing solution.

Searching keywords in JavaScript

Here's an example of the customer codes:
C000000123
C000000456
If I input C123 in the search box, "C000000123" will automatically display.
9 numbers are fixed.
Please help me, a short sample was shown to me but I don't get it.
function test(key, num, digit) {
let retStr;
xxxx (condition)
retun retStr;
}
here's an elaboration:
**
input:123
output:A00000123
input:1
output:A00000001
input:99999
output:A00099999
**
here's the detailed demand:
Since it takes time and effort to enter the management number “alphabet + numeric value 9 digits” on the search screen, when the alphabetic number and the number excluding the leading 0 are entered, it is automatically complemented so that it becomes 9 padded with zeros.
sorry i'm very very new to programming in javascript
Try this:
May be what you want...
Please test it and tell if its what you want.
function getOutput(input){
var str=input.substring(1,input.length);
var padd0=9-str.length;
var zr="000000000";
var zrsub=zr.substring(0,padd0);
var output=input[0]+zrsub+""+str;
return output;
}
//Example: Call it like (NB any letter can be used):
getOutput("C123"); //or
getOutput("D123");
You can use .endsWith in js which takes a string and a search string and returns true if the specified string ends with the search string.
This function takes an array of customer ids and a search string and returns the matching customer id
function searchCustomer(customers, searchString) {
return customers.find(customer => customer.endsWith(searchString));
}
searchCustomer(['C000000123', 'C000000456'], 123); // "C000000123"
searchCustomer(['C000000123', 'C000000456'], 456); // "C000000456"
searchCustomer(['C000000123', 'C000000456', 'A00000001'], 1); //"A00000001"

JavaScript regex: capturing optional groups while having a strict matching

I am trying to extract some data from user input that should follow this format: 1d 5h 30m, which means the user is entering an amount of time of 1 day, 5 hours and 30 minutes.
I am trying to extract the value of each part of the input. However, each group is optional, meaning that 2h 20m is a valid input.
I am trying to be flexible in the input (in the sense that not all parts need to be input) but at the same time I don't watch my regex to match some random imput like asdfasdf20m. This one should be rejected (no match).
So first I am getting rid of any separator the user might have used (their input can look like 4h, 10m and that's ok):
input = input.replace(/[\s.,;_|#-]+/g, '');
Then I am capturing each part, which I indicate as optional using ?:
var match = /^((\d+)d)?((\d+)h)?((\d+)m)?$/.exec(input);
It is kind of messy capturing an entire group including the letter when I only want the actual value, but I cannot say that cluster is optional without wrapping it with parentheses right?
Then, when an empty group is captured its value in match is undefined. Is there any function to default undefined values to a particular value? For example, 0 would be handy here.
An example where input is "4d, 20h, 55m", and the match result is:
["4d20h55m", "4d", "4", "20h", "20", "55m", "55", index: 0, input: "4d20h55m"]
My main issues are:
How can I indicate a group as optional but avoid capturing it?
How can I deal with input that can potentially match, like abcdefg6d8m?
How can I deal with an altered order? For example, the user could input 20m 10h.
When I'm asking "how to deal with x" I mean I'd like to be able to reject those matches.
As variant:
HTML:
<input type="text">
<button>Check</button>
<div id="res"></div>
JS:
var r = [];
document.querySelector('button').addEventListener('click', function(){
var v = document.querySelector('input').value;
v.replace(/(\d+d)|(\d+h)|(\d+m)/ig, replacer);
document.querySelector('#res').innerText = r;
}, false);
function trim(s, mask) {
while (~mask.indexOf(s[0])) {
s = s.slice(1);
}
while (~mask.indexOf(s[s.length - 1])) {
s = s.slice(0, -1);
}
return s;
}
function replacer(str){
if(/d$/gi.test(str)){
r[0] = str;
}
else if(/h$/gi.test(str)){
r[1] = str;
}
else if(/m$/gi.test(str)){
r[2] = str;
}
return trim(r.join(', '), ',');
}
See here.

Look for substring in a string with at most one different character-javascript

I am new in programing and right now I am working on one program. Program need to find the substring in a string and return the index where the chain starts to be the same. I know that for that I can use "indexOf". Is not so easy. I want to find out substrings with at moste one different char.
I was thinking about regular expresion... but not really know how to use it because I need to use regular expresion for every element of the string. Here some code wich propably will clarify what I want to do:
var A= "abbab";
var B= "ba";
var tb=[];
console.log(A.indexOf(B));
for (var i=0;i<B.length; i++){
var D=B.replace(B[i],"[a-z]");
tb.push(A.indexOf(D));
}
console.log(tb);
I know that the substring B and string A are the lowercase letters. Will be nice to get any advice how to make it using regular expresions. Thx
Simple Input:
A B
1) abbab ba
2) hello world
3) banana nan
Expected Output:
1) 1 2
2) No Match!
3) 0 2
While probably theoretically possible, I think it would very complicated to try this kind of search while attempting to incorporate all possible search query options in one long complex regular expression. I think a better approach is to use JavaScript to dynamically create various simpler options and then search with each separately.
The following code sequentially replaces each character in the initial query string with a regular expression wild card (i.e. a period, '.') and then searches the target string with that. For example, if the initial query string is 'nan', it will search with '.an', 'n.n' and 'na.'. It will only add the position of the hit to the list of hits if that position has not already been hit on a previous search. i.e. It ensures that the list of hits contains only unique values, even if multiple query variations found a hit at the same location. (This could be implemented even better with ES6 sets, but I couldn't get the Stack Overflow code snippet tool to cooperate with me while trying to use a set, even with the Babel option checked.) Finally, it sorts the hits in ascending order.
Update: The search algorithm has been updated/corrected. Originally, some hits were missed because the exec search for any query variation would only iterate as per the JavaScript default, i.e. after finding a match, it would start the next search at the next character after the end of the previous match, e.g. it would find 'aa' in 'aaaa' at positions 0 and 2. Now it starts the next search at the next character after the start of the previous match, e.g. it now finds 'aa' in 'aaaa' at positions 0, 1 and 2.
const findAllowingOneMismatch = (target, query) => {
const numLetters = query.length;
const queryVariations = [];
for (let variationNum = 0; variationNum < numLetters; variationNum += 1) {
queryVariations.push(query.slice(0, variationNum) + "." + query.slice(variationNum + 1));
};
let hits = [];
queryVariations.forEach(queryVariation => {
const re = new RegExp(queryVariation, "g");
let myArray;
while ((searchResult = re.exec(target)) !== null) {
re.lastIndex = searchResult.index + 1;
const hit = searchResult.index;
// console.log('found a hit with ' + queryVariation + ' at position ' + hit);
if (hits.indexOf(hit) === -1) {
hits.push(searchResult.index);
}
}
});
hits = hits.sort((a,b)=>(a-b));
console.log('Found "' + query + '" in "' + target + '" at positions:', JSON.stringify(hits));
};
[
['abbab', 'ba'],
['hello', 'world'],
['banana', 'nan'],
['abcde abcxe abxxe xbcde', 'abcd'],
['--xx-xxx--x----x-x-xxx--x--x-x-xx-', '----']
].forEach(pair => {findAllowingOneMismatch(pair[0], pair[1])});

Categories

Resources