Change char in a string in JavaScript - javascript

What regular expression should I use with the 'replace()' function in JavaScript to change every occurrence of char '_' in 0, but stop working as long as finding the char '.'?
Example:
_____323.____ ---> 00323._
____032.0____ --> 0032.0_
Are there ways more efficient than to use 'replace()'?
I am working with numbers. In particular, they can be both integer that float, so my string could never have two dots like in __32.12.32 or __31.34.45. At maximum just one dot.
What can I add in this:
/_(?=[\d_.])/g
to also find '_' followed by nothing?
Example: 0__ or 2323.43_
This does not work:
/_(?=[\d_.$])/g

You could use
str = str.replace(/[^.]*/,function(a){ return a.replace(/_/g,'0') })
Reference

Without replace/regex:
var foo = function (str) {
var result = "", char, i, l;
for (i = 0, l = str.length; i < l; i++) {
char = str[i];
if (char == '.') {
break;
} else if (char == '_') {
result += '0';
} else {
result += str[i];
}
char = str[i];
}
return result + str.slice(i);
}
With regex: dystroy
Benchmark for the various answers in this post:
http://jsperf.com/regex-vs-no-regex-replace

Unless you have some other obscure condition -
find:
_(?=[\d_.])
replace:
0
Or "To find also _ followed by nothing, example: 0__ or 2323.43_"
_(?=[\d_.]|$)

You could use lookahead assertion in regex...
"__3_23._45_4".replace(/_(?![^.]*$)/g,'0')
Result: 003023._45_4
Explanation:
/ # start regex
_ # match `_`
(?! # negative lookahead assertion
[^.]*$ # zero or more (`*`) not dots (`[^.]`) followed by the end of the string
) # end negative lookahead assertion
/g # end regex with global flag set

var str = "___345_345.4w3__w45.234__34_";
var dot = false;
str.replace(/[._]/g, function(a){
if(a=='.' || dot){
dot = true;
return a
} else {
return 0
}
})

Related

Remove last dots from characters in jquery

How to remove only the last dots in characters in jquery?
Example:
1..
1.2.
Expected result:
1
1.2
My code:
var maskedNumber = $(this).find('input.CategoryData');
var maskedNumberValue = $(maskedNumber).val().replace(/[^0-9.]/g, '').replace('.', 'x').replace('x', '.').replace(/[^\d.-]/g, '');
console.log(maskedNumberValue.slice(0, -1))
How do I solve this problem? Thanks
You can use regex replace for that:
function removeLastDot(value) {
return value.replace(/\.*$/, '')
}
console.log(removeLastDot('1..'))
console.log(removeLastDot('1.2.'))
In the example I use \.*$ regex:
$ - means that I want replace at the end of string
\.* - means that I want to match any number for . symbol (it is escaped cause . is special symbol in regex)
You can traverse the string with forEach and store the last index of any number in a variable. Then slice up to that variable.
let lastDigitIndex = 0;
for (let i = 0; i < str.length; i++) {
let c = str[i];
if (c >= '0' && c <= '9') lastDigitIndex = i;
};
console.log(str.slice(0, lastDigitIndex-1));
This will be an optimal solution.
maybe this can help.
var t = "1...";
while (t.substr(t.length - 1, 1) == ".") {
t = t.substr(0,t.length - 1);
}
import re
s = '1.4....'
# reverse the string
rev_s = s[::-1]
# find the first digit in the reversed string
if first_digit := re.search(r"\d", rev_s):
first_digit = first_digit.start()
# cut off extra dots from the start of the reversed string
s = rev_s[first_digit:]
# reverse the reversed string back and print the normalized string
print(s[::-1])
1.4
Add replace(/\.*$/g, '') to match one or more dots at the end of the string.
So your code would be like this:
var maskedNumberValue = $(maskedNumber).val().replace(/[^0-9.]/g, '').replace('.', 'x').replace('x', '.').replace(/[^\d.-]/g, '').replace(/\.*$/g, '');

regex replace for multiple string array javascript

I have a array of string and the patterns like #number-number anywhere inside a string.
Requirements:
If the # and single digit number before by hyphen then replace # and add 0. For example, #162-7878 => 162-7878, #12-4598866 => 12-4598866
If the # and two or more digit number before by hyphen then replace remove #. For example, #1-7878 => 01-7878.
If there is no # and single digit number before by hyphen then add 0. For example, 1-7878 => 01-7878.
I got stuck and how to do in JavaScript. Here is the code I used:
let arrstr=["#12-1676","#02-8989898","#676-98908098","12-232","02-898988","676-98098","2-898988", "380100 6-764","380100 #6-764","380100 #06-764"]
for(let st of arrstr)
console.log(st.replace(/#?(\d)?(\d-)/g ,replacer))
function replacer(match, p1, p2, offset, string){
let replaceSubString = p1 || "0";
replaceSubString += p2;
return replaceSubString;
}
I suggest matching # optionally at the start of string, and then capture one or more digits before - + a digit to later pad those digits with leading zeros and omit the leading # in the result:
st.replace(/#?\b(\d+)(?=-\d)/g, (_,$1) => $1.padStart(2,"0"))
See the JavaScript demo:
let arrstr=["#12-1676","#02-8989898","#676-98908098","12-232","02-898988","676-98098","2-898988", "380100 6-764","380100 #6-764","380100 #06-764"]
for(let st of arrstr)
console.log(st,'=>', st.replace(/#?\b(\d+)(?=-\d)/g, (_,$1) => $1.padStart(2,"0") ))
The /#?\b(\d+)(?=-\d)/g regex matches all occurrences of
#? - an optional # char
\b - word boundary
(\d+) - Capturing group 1: one or more digits...
(?=-\d) - that must be followed with a - and a digit (this is a positive lookahead that only checks if its pattern matches immediately to the right of the current location without actually consuming the matched text).
Using the unary operator, here's a two liner replacer function.
const testValues = ["#162-7878", "#12-4598866", "#1-7878", "1-7878"];
const re = /#?(\d+?)-(\d+)/;
for(const str of testValues) {
console.log(str.replace(re, replacer));
}
function replacer(match, p1, p2) {
p1 = +p1 < 10 ? `0${p1}` : p1;
return `${p1}-${p2}`;
}
let list_of_numbers =["#1-7878", "#162-7878", "#12-1676","#02-8989898","#676-98908098","12-232","02-898988","676-98098","2-898988"]
const solution = () => {
let result = ''
for (let number of list_of_numbers) {
let nums = number.split('-')
if (nums[0][0] == '#' && nums[0].length > 2) {
result = `${nums[0].slice(1, number.length-1)}-${nums[1]}`
console.log(result)
} else if (nums[0][0] == '#' && nums[0].length == 2) {
result = `${nums[0][0] = '0'}${nums[0][1]}-${nums[1]}`
console.log(result)
} else {
console.log(number)
}
}
}
I think a simple check is what you should do with the match function.
let arrstr=["#12-1676","#0-8989898","#676-98908098","12-232","02-898988","676-98098","2-898988"];
const regex = /#\d-/g;
for(i in arrstr){
var found = arrstr[i].match(regex);
if(found){
arrstr[i]=arrstr[i].replace("#","0")
}else{
arrstr[i]=arrstr[i].replace("#","")
}
}
console.log(arrstr);
or if you really want to stick with the way you have it.
let arrstr=["#12-1676","#02-8989898","#6-98908098","12-232","02-898988","676-98098","2-898988"]
for(let st of arrstr)
console.log(st.replace(/#(\d)?(\d-)/g ,replacer))
function replacer(match, p1, p2, offset, string){
let replaceSubString = p1 || "0";
replaceSubString += p2;
return replaceSubString;
}
remove the '?' from the regex so its not #? but just #

Partially mask email address - javascript

How can I partially hide email address like this in Javascript?
examplemail#domain.com => ex**pl**ai*#domain.com
I have modify the below code, but can get the result that I need, it's just return this result:
exam*******#domain.com
email.replace(/(.{4})(.*)(?=#)/, function (gp1, gp2, gp3) {
for (let i = 0; i < gp3.length; i++) {
gp2 += "*";
}
return gp2;
});
You could seach for a group of four characters and replace a group of two until you found an # sign-
const
mask = string => string.replace(
/(..)(.{1,2})(?=.*#)/g,
(_, a, b) => a + '*'.repeat(b.length)
);
console.log(mask('examplemail#domain.com'));
This would be one way to solve your problem:
function f(mail) {
let parts = mail.split("#");
let firstPart = parts[0];
let encrypt = firstPart.split("");
let skip = 2;
for (let i = 0; i < encrypt.length; i += 1) {
if (skip > 0) {
skip--;
continue;
}
if (skip === 0) {
encrypt[i] = "*";
encrypt[i + 1] = "*";
skip = 2;
i++;
}
}
let encryptedMail = `${encrypt.join("")}#${parts.slice(1)}`;
return encryptedMail;
}
Simply do this
function maskFunc(x) {
var res = x.replace(/(..)(.{1,2})(?=.*#)/g,
(beforeAt, part1, part2) => part1 + '*'.repeat(part2.length)
);
return res
}
console.log(maskFunc('emailid#domain.com'));
As a regex for the accepted answer, I would suggest making sure to match only a single # sign by making use of a negated character class [^\s#] matching any char except a whitespace char or an # itself.
This way you might also use it for multiple email addresses, because using (?=.*#) with multiple # signs can give unexpected results.
([^\s#]{2})([^\s#]{1,2})(?=[^\s#]*#)
Regex demo
In the pattern that you tried, you matched 4 times any char using (.{4}). Repeating 4 chars might be done using a positive lookbehind. Then you could get the match only without groups.
First assert a whitespace boundary to the left. Then start with an offset of 2 chars, optionally repeated by 4 chars.
Then match 1 or 2 chars, asserting an # to the right.
const partialMask = s => s.replace(
/(?<=(?<!\S)[^\s#]{2}(?:[^\s#]{4})*)[^\s#]{1,2}(?=[^\s#]*#)/g,
m => '*'.repeat(m.length)
);
console.log(partialMask("examplemail#domain.com"));
If you want to only replace the digits close to the # and allow it to add * base on the length, you can do this
const separatorIndex = email.indexOf('#');
if (separatorIndex < 3)
return email.slice(0, separatorIndex).replace(/./g, '*')
+ email.slice(separatorIndex);
const start = separatorIndex - Math.round(Math.sqrt(separatorIndex)) - 1;
const masked = email.slice(start, separatorIndex).replace(/./g, '*');
return email.slice(0, start) + masked + email.slice(separatorIndex);

Finding the index to a non-specified character

Let's say for example I have a string
thisIsThisTuesday Day
I want to find the index of all the capital letters, test if there is a space before it, and if not insert one. I would need the index of each one.
At least from what I can see indexOf(String) will only produce the index of the first occurance of the character T/t
This :
for(i=0;i<str.length;i++){
let char=str[i];
if(isNaN(char*1)&&char==char.toUpperCase()){
y=str.indexOf(char);
console.log(char,y)
}
}
would produce the capital letters, and their indexes but will only display the first occurrence of the character in question. I feel pretty confident that the part I am missing is a for() loop in order to move the index iteration..but it escapes me.
Thank you in advance!
You can use a regex:
It matches any non-whitespace character followed by a capital letter and replaces it by the two characters with a space between.
const str = "thisIsThisTuesday Day";
const newstr = str.replace(/([^ ])([A-Z])/g, "$1 $2");
console.log(newstr);
You can use the following regular expression:
/(?<=\S)(?=[A-Z])/g
The replace will insert spaced between characters which are non-space followed by a capital letter.
See example below:
let str = "thisIsThisTuesday Day";
const res = str.replace(/(?<=\S)(?=[A-Z])/g, ' ');
console.log(res);
Note: As pointed out ?<= (positive lookbehind) is currently not be available in all browsers.
Actually, the String.indexOf function can take a second argument, specifying the character it should start searching from. Take a look at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf
But, if you just want to find all capital letters and prefix them with a space character, if one is not found, there are many approaches, for example:
var str = "thisIsThisTuesday Day";
var ret = '';
for (var i=0; i<str.length; i++) {
if (str.substr(i, 1) == str.substr(i, 1).toUpperCase()) {
if ((i > 0) && (str.substr(i - 1,1) != " "))
ret += " ";
}
ret += str.substr(i,1);
}
After running this, ret will hold the value "this Is This Tuesday Day"
You could iterate over the string and check if each character is a capital. Something like this:
const s = 'thisIsThisTuesday Day';
const format = (s) => {
let string = '';
for (let c of s) {
if (c.match(/[A-Z]/)) string += ' ';
string += c;
}
return string;
};
console.log(format(s));
Or alternatively with reduce function:
const s = 'thisIsThisTuesday Day';
const format = (s) => s.split('').reduce((acc, c) => c.match(/[A-Z]/) ? acc + ` ${c}` : acc + c, '');
console.log(format(s));

Regexp search not surrounded by

I want to find all occurences of % that are not within quotation characters.
Example> "test% testing % '% hello' " would return ["%","%"]
Looking at another stack overflow thread this is what I found:
var patt = /!["'],*%,*!['"]/g
var str = "testing 123 '%' % '% ' "
var res = str.match(patt);
However this gives me null. Have you any tips of what I should do?
Demo
You could try the below positive lookahead assertion based regex.
> var s = "test% testing % '% hello' "
> s.match(/%(?=(?:[^']*'[^']*')*[^']*$)/g)
[ '%', '%' ]
> var str = "testing %"
undefined
> str.match(/%(?=(?:[^']*'[^']*')*[^']*$)/g)
[ '%' ]
> var str1 = "testing '%'"
undefined
> str1.match(/%(?=(?:[^']*'[^']*')*[^']*$)/g)
null
Try this:
var patt= /[^"'].*?(%).*?[^'"]/g ;
var str = "testing 123 '%' % '% ' "
var res = str.match(patt);
console.dir(res[1]); // result will be in the 1st match group: res[1]
Here is the link to the online testing.
Explanation:
[^"'] - any character except " or '
.*? any characters (except new line) any times or zero times not greedy.
Update
Actually you must check if behing and ahead of % there are no quotes.
But:
JavaScript regular expressions do not support lookbehinds
So you have no way to identify " or ' preceding % sign unless more restrictions are applied.
I'd suggest to do searching in php or other language (where lookbehind is supported) or impose more conditions.
Since I'm not a big fan of regular expressions, here's my approach.
What is important in my answer, if there would be a trailing quote in the string, the other answers won't work. In other words, only my answer works in cases where there is odd number of quotes.
function countUnquoted(str, charToCount) {
var i = 0,
len = str.length,
count = 0,
suspects = 0,
char,
flag = false;
for (; i < len; i++) {
char = str.substr(i, 1);
if ("'" === char) {
flag = !flag;
suspects = 0;
} else if (charToCount === char && !flag) {
count++;
} else if (charToCount === char) {
suspects++;
}
}
//this way we can also count occurences in such situation
//that the quotation mark has been opened but not closed till the end of string
if (flag) {
count += suspects;
}
return count;
}
As far as I believe, you wanted to count those percent signs, so there's no need to put them in an array.
In case you really, really need to fill this array, you can do it like that:
function matchUnquoted(str, charToMatch) {
var res = [],
i = 0,
count = countUnquoted(str, charToMatch);
for (; i < count; i++) {
res.push('%');
}
return res;
}
matchUnquoted("test% testing % '% hello' ", "%");
Trailing quote
Here's a comparison of a case when there is a trailing ' (not closed) in the string.
> var s = "test% testing % '% hello' asd ' asd %"
> matchUnquoted(s, '%')
['%', '%', '%']
>
> // Avinash Raj's answer
> s.match(/%(?=(?:[^']*'[^']*')*[^']*$)/g)
['%', '%']
Use this regex: (['"]).*?\1|(%) and the second capture group will have all the % signs that are not inside single or double quotes.
Breakdown:
(['"]).*?\1 captures a single or double quote, followed by anything (lazy) up to a matching single or double quote
|(%) captures a % only if it wasn't slurped up by the first part of the alternation (i.e., if it's not in quotes)

Categories

Resources