Regex to find matches except in last n characters of input - javascript

I have to replace the digits in the first (n-4) characters of credit card with '*'.
I am using following three lines of code.
var cardnumber = '1A2C3GF4DS84Ff';
last4digits = cardNumber.substring(cardNumber.length-4);
prevdigits = cardNumber.substring(0, cardNumber.length-4).replace(/[0-9]/g,'*');
$cache.cardNumber.val( prevdigits + last4digits);
Just wondering can I do it in just one line of code by using regex.

Use a look-ahead to ensure that there are at least four remaining characters after the digit. In other words, digits within the last four characters will not match:
var regexp = /\d(?=....)/g;
> cardnumber.match(regexp)
< ["1", "2", "3", "4"]
To replace with asterisks:
> cardnumber.replace(regexp, '*')
< "*A*C*GF*DS84Ff"
Information on look-aheads is here.

From here I got this code.
var text = '1ab2cb3cd4ab5cb6cd7';
var matches = text.match(/(\d)/g);
for (i=0; i<matches.length; i++) {
alert(matches[i]);
}
Actually, they wanted to extract digits too. I don't need to change the regex.
You can limit it to 5 by making the loop start with:
for (i=0; i<matches.length && i < 5; i++){

Just use (\d) and check it programmatically afterwards.

var y= x.replace(/\D/g, '').substring(0, 5);

The .replace() function can use a function as the replacement, and it will be called for each match. It can keep a counter and return something different based on the counter.
var str = '1A2C3GF4DS84Ff';
var digits = 0;
var newstr = str.replace(/\d/g, function(match) {
if (digits++ < 4) {
return '*';
} else {
return match;
}
});
document.write(newstr);

looks like following one does the job You need:
var text= '1A2B3C4D5E6F',
n = 5;
text = text.replace(/\d/g, function ($1){
return n-- ?'*' : $1
});

Related

Function to capitalize first and last letter of each word not working

I created a function that given any string will return the string with the first and last letter of each word capitalized. So far it works in some words, not on others, can someone help me figure out why?
function Capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
//For every word
for (let j = 0; j < spl[i].length; j++) {
//For every letter in each word
var word = spl[i];
var size = spl[i].length;
var firstLetterCapital = word.replace(word[0], word[0].toUpperCase()); //Creates new array
var LastLetterCapital = firstLetterCapital.replace(
word[size - 1],
word[size - 1].toUpperCase()
);
}
words.push(LastLetterCapital);
}
console.log(words.join(" "));
}
Capitalize("hello there");
It works when I type : Capitalize("my name is john smith"), but not with Capitalize("hello there")
I know it's a complete mess and probably a very bad way to do it, but I started programming a month ago so give me a break :)
#symlink has already explained why it is "HellO ThEre" instead of "Hello TherE". He also has given a solution to explicitly target first and last character of the string. I have accomplished not much different than already posted by members, except for .. "may be" a little more explanation.
You can break the entire problem in these four steps.
Get all the words into an array.
Create a function, that takes each word and targets first and last character, changes it and returns the changed word.
Apply a mapping step using the function created above (in step 2) to the entire array of words (obtained in step 1).
Join the transformed array, obtained in step 3, using a blank space as a separator.
I have written two functions that accomplish this task. I am sorry for long name of functions. It helps me keep track of things in a complex program (especially when I am in a hurry!).
Step 2 function
function Capitalize_FirstAndLast_One_Word(word){
// Split the string in array for easy access/manipulation by indexing
Split_String = word.split("")
// Target the first word
Split_String[0] = Split_String[0].toUpperCase();
// Target the last word
Split_String[Split_String.length - 1] = Split_String[Split_String.length - 1].toUpperCase();
// Join the array into a single word
Joined_Back = Split_String.join("")
return Joined_Back;
}
Step 1, 3 and 4 function
function Capitalize_Entire_String(str){
Regular_Exp = new RegExp(/\w+/g);
//Below is step 1
MatchedArray = str.match(Regular_Exp);
//Below is step 3
ConvertedArray = MatchedArray.map(Capitalize_FirstAndLast_One_Word);
// Below is step 4
ReturnedString = ConvertedArray.join(" ");
console.log(ReturnedString);
return ReturnedString;
}
Now you have everything. You can use the function like below.
Capitalize_Entire_String("hello there");
Capitalize_Entire_String("hello there this is a test");
Hope this helps. I am sorry if this turned out to be a redundant answer for you.
Reason your code don't work is the use of replace(). replace() will always replace the first character found.
There is absolutely no reason to run a nested loop. You can achieve this using a single loop.
function cap(str){
let spl = str.split(' ');
for(let i = 0; i < spl.length; i++){
let temp = spl[i];
temp = temp[0].toUpperCase() + temp.slice(1)
temp = temp.slice(0,-1) + temp[temp.length - 1].toUpperCase();
spl[i] = temp;
}
return spl.join(' ');
}
console.log(cap("a quick brown fox"))
An easier way is to use map() and template strings.
const cap = str => str
.split(' ')
.map(x => (
x.length === 1 ?
x.toUpperCase() :
`${x[0].toUpperCase()}${x.slice(1,-1)}${x[x.length -1].toUpperCase()}`)
)
.join(' ')
console.log(cap("a quick brown fox"))
To simplify the function, you could split the string into an array, map each word to the desired format, and join it together into a string again.
function Capitalize(str){
return str.split(" ").map((word) => word.charAt(0).toUpperCase() +
(word.length > 2 ? word.substring(1, word.length - 1) : "") +
(word.length > 1 ? word.charAt(word.length - 1).toUpperCase() : "")).join(" ");
}
console.log(Capitalize("i want to capitalize first and last letters"));
Congrats on starting out programming...
You can use this to achieve what you want to do
function capitalizeFirstAndLastLetters (str) {
const words = str.split(" "); // Split the string into words
const modified = [];
for (const word of words) {
if (word.length <= 2) {
modified.push(word.toUpperCase()); // If the word less than 3 characters, the whole word is capitalized
continue;
}
var firstCapital = word[0].toUpperCase(); // word[0] gets the first index of the string (I.e. the first letter of the word)
var lastCapital = word.slice(-1).toUpperCase(); // The slice function slices a portion of the word. slice(-1) gets the last letter
var middlePart = word.slice(1, -1); // slice(1, -1) means start slicing from the second index (I.e. 1) and ignore the last index
modified.push(firstCapital + middlePart + lastCapital);
}
return modified.join(" "); // Join each element in the modified array with a space to get the final string with each words first and last letters capitalized
}
capitalizeFirstAndLastLetters("hello there I am a boy"); // "HellO TherE I AM A BoY"
Try this, it worked for hello world because I guess you want the outcome to be HellO TherE right?:
function capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
//For every word
let changedWord = "";
for (let j = 0; j < spl[i].length; j++) {
//For every letter in each word
if(j == 0 || j == spl[i].length - 1) {
changedWord += spl[i][j].toUpperCase();
} else {
changedWord += spl[i][j].toLowerCase();
}
}
words.push(changedWord);
console.log(words);
}
console.log(words.join(" "));
}
capitalize("hello there");
ALSO: Make your functions name start with lowercase letter. Thats just how it is. Starting with uppercase letters usually are Classes. Just a quick tip
Maybe this does what you want, don't want to change much from your code:
function Capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
var word = spl[i];
var firstCapital = word[0].toUpperCase(); // get first character after capitalizing
var lastCapital = word.slice(-1).toUpperCase(); // get last character after capitalizing
var midOriginal = word.slice(1, -1);
words.push(firstCapital + midOriginal + lastCapital) // concat 3 parts
}
console.log(words.join(" "));
}
Capitalize("hello there");
This expression:
var LastLetterCapital = firstLetterCapital.replace(
word[size - 1],
word[size - 1].toUpperCase()
);
Is replacing the first occurrence of the character "e" in "There" with an uppercase "E".
Explanation
The replace() function first translates the first param: word[size - 1] to the literal character "e", then replaces the first occurrence of that character with the uppercase "E", resulting in the string "ThEre".
Solution
Use a regular expression as your first parameter instead, to ensure that the last character is targeted, regardless of whether or not that same character shows up anywhere else in the word:
var LastLetterCapital = firstLetterCapital.replace(/.$/, word[size - 1].toUpperCase());
function Capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
//For every word
var word = spl[i];
var size = spl[i].length;
for (let j = 0; j < size; j++) {
//For every letter in each word
var firstLetterCapital = word.replace(word[0], word[0].toUpperCase()); //Creates new array
var LastLetterCapital = firstLetterCapital.replace(/.$/, word[size - 1].toUpperCase());
}
words.push(LastLetterCapital);
}
console.log(words.join(" "));
}
Capitalize("hello there");
This should do the trick:
function Capitalize(str) {
return str.replace(/(\b\w|\w\b)/g, l => l.toUpperCase())
}
console.log(Capitalize('i want to be capitalized in a rather strange way'))
Explanation:
In the regular expression /(\b\w|\w\b)/g, \b means "word boundary" and \w means "word character", so (\b\w|\w\b) matches a word boundary followed by a word character OR a word character followed by a word boundary (i.e. the first and last character of words).
The matches of this expression are then passed to the inline function l => l.toUpperCase() (which itself is the second argument to replace) that capitalizes the passed letter.
the string type is immutable, so why don't you try to convert the string to an array like y = word.split('') and do y[0] = word.charAt(0).toUpperCase() and then convert back to string with y.join('')

How to insert symbol when encountering duplicates in a string

Lets assume that I have this string: aabbc and between every character which is not equal to the prior character I want to insert a symbol.
Which would result in the following string: aa$bb$c
How can this be achived?
You can do that in following steps:
You can convert string to array using Spread Operator
Then use map() on it
Inside map() check if the element on next to current is not same as current letter then add $ at its end.
Use join() to make array a string.
Remove the last $ using slice() which is extra.
let str = 'aabbc';
let res = [...str].map((x,i,arr) => arr[i+1] !== arr[i] ? x + '$' : x).join('').slice(0,-1)
console.log(res)
You can also use RegExp and match()
let str = 'aabbc';
let res = str.match(/(.)(\1*)/g).join('$')
console.log(res)
Can be done with a single replace:
input.replace(/(.)(?!\1)(?=.)/g, "$1$$")
Explanation of the pattern:
. - matches any single character (except newline); let's call this character X.
(.) - capturing subpattern; captures X so that it can be referenced in the replacement string (explained below).
\1 - backreference; matches another character identical to X.
(?!\1) - negative look-ahead; matches only if the X matched so far, is not followed by another X.
(?=.) - positive look-ahead; matches only if the X matched so far, is followed by any other character; in other words, asserts that the line does not end here. Can be omitted if you don't mind having a trailing $ appended.
Explanation of the replacement string:
$1 - the X captured by the first capturing subpattern (see above).
$$ - a single $.
Example:
var input = "aabbc";
var out = input.replace(/(.)(?!\1)(?=.)/g, "$1$$");
console.log(out);
Maybe try to do:
var charArray = myString.split(''); //this should split the string in an array of the characters. ["a", "a", "b", "b", "c"]
var newString = "";
for (int i = 0; i < charArray.length -1; i++) { //I do length -1 so to not cause an IndexOutOfBoundException at charArrayi+1]
if (charArray[i] === charArray[i+1]) {
newString += charArray[i] + charArray[i+1] + "$";
}
}
Something like that maybe?
I haven't actually tested this, I just typed it in here.
But in my head this feels right. :)
const a = 'aabbc';
let last = '';
let str = '';
for (let i = 0; i < a.length; i += 1) {
str += a[i];
if (last === a[i]) {
str += '$';
}
last = a[i];
}
console.log(str);
You can do this by using simple for loop as mentioned below:
var string = "aabbc";
var checkChar = "";
for (let i = 0; i < string.length; i++) {
checkChar += string.charAt(i);
if (string.charAt(i - 1) === string.charAt(i)){
checkChar += "$";
}
}
console.log(checkChar)

String Matching Javascript

I want to get the characters after # symbol till a space character.
for eg. if my string is like hello #world. some gibberish.#stackoverflow. Then I want to get the characters 'world' and 'stackoverflow'.
Here is what I have been trying.
var comment = 'hello #world. some gibberish.#stackoverflow';
var indices = [];
for (var i = 0; i < comment.length; i++) {
if (comment[i] === "#") {
indices.push(i);
for (var j = 0; j <= i; j++){
startIndex.push(comment[j]);
}
}
}
I can get the occurences of # and spaces and then trim that part to get my content but I'd like a better solution / suggestion for this, with without REGEX. Thanks in advance.
You can use this regex:
/#(\S+)/g
and grab captured groups using exec method in a loop.
This regex matches # and then \S+ matches 1 or more non-space characters that are grouped in a captured group.
Code:
var re = /#(\S+)/g;
var str = 'hello #world. some gibberish.#stackoverflow';
var m;
var matches=[];
while ((m = re.exec(str)) !== null) {
matches.push(m[1]);
}
document.writeln("<pre>" + matches + "</pre>");
PS: Note you will need to use
/#([^.\s]+)/g
if you don't want to capture DOT after word.

Replacing multiple characters in a string with a string rewrites characters

I have a variable (in this example var str = "I!%1$s-I!%2$s TTL!%3$s";), in which I want to replace the % with elements from an array (var regex = ['aaa', 'bbb', 'ccc'];).
I google around a bit and found this solution, but I'm having trouble implementing it. My problem is that I want to replace a single character with multiple characters, and then continue the string, but this just overwrites the characters. I actually have no idea why.
Any help is appreciated, my code below
String.prototype.replaceAt = function(index, character) {
return this.substr(0, index) + character + this.substr(index + character.length);
}
var str = "I!%1$s-I!%2$s TTL!%3$s";
var regex = ['replace', 'replace', 'replace'];
//find position of %
var find = /%/gi,
result, pos = [];
while ((result = find.exec(str))) {
pos.push(result.index);
}
//replace % with regex elements
for (x = 0; x < pos.length; x++) {
str = str.replaceAt(pos[x], regex[x]);
}
document.write(str);
Use replacement function, like this
var str = "I!%1$s-I!%2$s TTL!%3$s";
var regex = ['[123]', '[456]', '[789]'];
console.log(str.replace(/%(\d+)/g, function(match, group1) {
return regex[parseInt(group1) - 1] + group1;
}));
// I![123]1$s-I![456]2$s TTL![789]3$s
The RegEx /%(\d+)/g matches anything of the pattern % followed by one or more digits. And it captures the digits as a group. Then the exact match and the group is passed to the function to get the actual replacement. In the function, you convert the group to a number with parseInt and return the respective value from the regex array.

Split long words into equal-length pieces

How can I use JavaScript to split extremely long words? I am not looking for a CSS solution like word-break: break-all. The goal is to insert spaces in long words to break them into smaller pieces. The solution should be as fast as possible, since it will be called thousands of times in a few seconds.
Example how the solution should work:
splitString("This is an exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxample string.");
=> This is an exxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxample string.
splitString("AnotherExammmmmmmmmmmpleeeeeeeeeeeeeeeee");
=> AnotherExammmmmm mmmmmpleeeeeee eeeeeeeeee
Any words that are too long are split with a space character.
It would be even better if the resulting pieces were of roughly equal length.
Since you asked for performance, I compared a regex approach:
function splitString(str, length) {
var regex = new RegExp("/(\w{" + length + "})(?=\w)/g");
return str.replace(regex, "$1 ");
}
with this relatively simple handmade solution:
function splitString(str, length) {
var words = str.split(" ");
for (var j = 0; j < words.length; j++) {
var l = words[j].length;
if (l > length) {
var result = [], i = 0;
while (i < l) {
result.push(words[j].substr(i, length))
i += length;
}
words[j] = result.join(" ");
}
}
return words.join(" ");
}
JsPerf says that the regex version is roughly 8% faster on my machine (Mac Opera16). As this is also more concise, I would go for it.
While this does nothing to ensure that the pieces are of equal length, it will ensure no word in your string is longer than 40 characters.
'This is an exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxample string.'
.replace(/(\w{40})(?=\w)/g, '$1 ');
>> 'This is an exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xample string.'
A "word" is defined here as a consecutive string of letters, numbers, and underscores. If you wish to apply a different definition of "word" (e.g., if your "words" can contain Unicode characters), you will need to swap \w for the character class of your choice.
Here's what I came up with:
http://jsfiddle.net/KyleMuir/czBZz/
function splitString(value) {
var tooLongDeterminer = 12;
var words = value.split(' ');
for (var i = words.length - 1; i >= 0; i--) {
if (words[i].length > tooLongDeterminer) {
var split = words[i];
var tempArray = new Array();
while (split != '') {
var word = splitWord(split, tooLongDeterminer);
tempArray.push(word);
split = split.replace(word, '');
}
words.splice(i, 1, tempArray.join(' '));
}
}
return words.join(' ');
}
function splitWord(word, length) {
return word.substring(0, length);
}
console.log(splitString("This is an exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxample string."));
console.log(splitString("AnotherExammmmmmmmmmmpleeeeeeeeeeeeeeeee"));
Note: this is recursive (and only tested on chrome) so may or may not suit your purposes but the output from the above console.logs are as follows:
AnotherExamm mmmmmmmmmple eeeeeeeeeeee eeee
This is an exxxxxxxxxxx xxxxxxxxxxxx xxxxxxxxxxxx xxxxxample string.
Hope this helps and thanks for the challenge :)

Categories