Javascript Regex Custom Replace - javascript

How do I get the following conversion using Regex?
Content(input data structure):
a-test
b-123
c-qweq
d-gdfgd
e-312
Conversion:
1-test
2-123
3-qweq
4-gdfgd
Final-312
var index = 1;
function c_replace() {
if(index == 5) { return "Final"; }
return index++;
}

there you go :D
// i assume you have a string input that contains linebreaks due to your question format
const input = `a-test
b-123
c-qweq
d-gdfgd
e-312`.trim(); // removing whitespace in front or behind the input data.
//splitting the lines on whitespace using \s+
const output = input.split(/\s+/).map((s, i, a) => {
// this will map your pattern asd-foooasdasd
const data = s.match(/^[a-z]+-(.+)$/);
// you may want to tweak this. right now it will simply throw an error.
if (!data) throw new Error(`${s} at position ${i} is a malformed input`);
// figure out if we are in the final iteration
const final = i == a.length -1;
// the actual output data
return `${final ? "Final" : (i + 1)}-${data[1]}`;
// and of course join the array into a linebreak separated list similar to your input.
}).join("\n");
console.log(output);

Test
var index=1;
var text=`a-test
b-123
c-qweq
d-gdfgd
e-312`;
function c_replace() {
if(index == 5) { return "Final-"; }
return index++ +'-';
}
console.log(text.replace(/.-/g,c_replace));

var input = [
'a-test',
'b-123',
'c-qweq',
'd-gdfgd',
'e-312'
];
var output = input.map((e, i) => ++i + e.slice(1));
output[output.length - 1] = 'Final' + output[output.length - 1].slice(1);
console.log(output);

Related

Splitting string that's really an array?

I'm trying to split this string
var raw = "GMYTEOR[RHE5DO,SG[A5D[CN[I,Q],EM[I,Q],M],E5D[C[NY,OA],O,Q],M5DC[MY,NA],U5DQ,Y5DCOA]]"
I manually split this out into the following patterns:
const valid_reults = [
'GMYTEORRHE5DO',
'GMYTEORSGA5DCNI',
'GMYTEORSGA5DCNQ',
'GMYTEORSGA5DEMI',
'GMYTEORSGA5DEMQ',
'GMYTEORSGA5DM',
'GMYTEORSGE5DCNY',
'GMYTEORSGE5DCOA',
'GMYTEORSGE5DO',
'GMYTEORSGE5DQ',
'GMYTEORSGM5DCMY',
'GMYTEORSGM5DCNA',
'GMYTEORSGU5DQ',
'GMYTEORSGY5DCOA',
]
I tried parsing it with JSON.parse but that didnt work for obvious reasons.
I also tried splitting the string by the brackets but that was a really bad idea and I couldn't get it working after 20-30 mins of trying.
What's the best way to convert that bizarre string format into a formatted array as shown in valid_results?
This should work:
function splitString(str) {
// if there is no brackets a split will solve
if (!str.includes('[')) {
return str.split(',');
}
// finds first bracket
const bracketsIdx = str.indexOf('[');
// find the close bracket for it
const closingBracketsIdx =
findClosingBracketMatchIndex(str, bracketsIdx);
if (closingBracketsIdx === -1) {
// Invalid input, didn't find a close bracket
throw Error()
}
// find all possibilities inside the bracket
const expand = splitString(str.substring(
bracketsIdx+1,
closingBracketsIdx,
));
return [
// Remove duplicates
...new Set(expand.map(
(expandedStr) => splitString(
(
// concatenate each possibility to what is
// outside of the bracket
str.substring(
0,
bracketsIdx,
)
+ expandedStr
+ str.substring(
closingBracketsIdx+1,
)
)
)
// since each call will return an array we flatten them
).flat())
];
}
function findClosingBracketMatchIndex(str, pos) {
let openBracketCount = 1;
for (let i = pos + 1; i < str.length; i++) {
let char = str[i];
if (char === '[') {
openBracketCount++;
} else if (char === ']') {
openBracketCount--;
}
if (openBracketCount === 0){
return i;
}
}
return -1;
}

How do I return only the letter that repeats the most times?

How do I return only the letter that repeats the most times? How to make it return only the result e = 5 in the following case
enter code here
var s = "Teeeeessttt"
var x = (s.toLowerCase());
function count() {
array_elements = ([...x]);;
array_elements.sort();
var current = null;
var cnt = 0;
for (var i = 0; i < array_elements.length; i++) {
if (array_elements[i] != current) {
if (cnt > 0) {
document.write(current + ' - ' + cnt + '<br>');
}
current = array_elements[i];
cnt = 1;
} else {
cnt++;
}
}
if (cnt > 0) {
document.write(current + ' - ' + cnt);
}
}
count();
First you would need to count the amount of times a character occurs. You could use the reduce method to loop over each character and store that character as a key in an object. The value of the key should represent the amount of times the character has occurred.
It would look like the object below.
{
"t": 4,
"e": 5,
"s": 2
}
From here you want to look for the highest number and return the key that corresponds to it. I've borrowed the solution of this SO thread to get the highest count of the object using another reduce loop.
const string = "Teeeeessttt";
const mostOccuringCharacter = string => {
// Count the occurence of each character.
const count = [...string.toLowerCase()].reduce((counter, char) => {
counter[char] = (counter[char] || 0) + 1;
return counter;
}, {});
// Compare the values with each other and return the
// character with the highest count.
const highestChar = Object.keys(count).reduce((a, b) =>
count[a] > count[b] ? a : b);
// Return an array with the character and the count.
return [highestChar, count[highestChar]]
};
const [ char, count ] = mostOccuringCharacter(string);
console.log(`${char} = ${count}`);
#UKS points out a dupe for this, interestingly there was a post with issues with funcky unicode.. eg. πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸ»πŸ‘¦πŸ½πŸ‘¦πŸΎπŸ‘¦πŸΏ, but no solution was shown for this.
So with that in mind I thought I would knock up a version that handles unicode nicely. I've also split into multiple functions for re-use. As you can see it's also easy to alter to find the least used character if so wanted. Not sure if this will handle 100% unicode, there might be some even more funcky ones. :)
function unicodeStrSplit(str) {
const x = [...str];
//let handle some funcky unicode
for (let p=x.length-1;p>0;p--)
if(x[p].charCodeAt(0)===0xd83c){x[p-1] += x[p], x.splice(p, 1) };
return x;
}
function arrayCounter(arr) {
return [...arr.reduce((a,v)=>a.set(v,a.get(v)+1||1),new Map())].
sort((a,b) => b[1]-a[1]);
}
function stringCounter(str) {
return arrayCounter(unicodeStrSplit(str));
}
console.log(stringCounter("Teeeeessttt").shift()); //first array item
//funcky unicode too.
console.log(stringCounter('πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸ»πŸ‘¦πŸ½πŸ‘¦πŸΎπŸ‘¦πŸΏ').shift()); //first array item
//also let's get the least used
console.log(stringCounter('πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸ»πŸ‘¦πŸ½πŸ‘¦πŸΎπŸ‘¦πŸΏ').pop()); //last array item

Search Placeholder Values in 2 strings

I've two strings in JavaScript like
var description = "<DP_A>.<Del.Dce Lks.{Link}>.<Pl.Rrs Bk 0.310-PT-304_({strm})>"
var Title = "<DP_A>.<Del.Dce Lks.1>.<Pl.Rrs Bk 0.310-PT-304_(1)>"
here {Link} and {strm} are placeholders or more likely whatever comes between { } is placeholder
I need to compare both string like description and Title to find placeholder values, Output needs to be like
{"Link" : 1, "strm" : 1 }
or array
[{Link" : 1, "strm" : 1}]
I've tried some RegEx but not working, any help??
if (description.includes("{")) {
var found = [], // an array to collect the strings that are found
rxp = /{([^}]+)}/g,
curMatch;
while (curMatch = rxp.exec(description)) {
found.push(curMatch[1]);
}
}
I'm able to get array of Placeholders but not able to find values into title string.
You could get all parts and then splice the values out of the title string.
"<DP_A>.<Del.Dce Lks.{Link}>.<Pl.Rrs Bk 0.310-PT-304_({strm})>",
"<DP_A>.<Del.Dce Lks. 1 >.<Pl.Rrs Bk 0.310-PT-304_( 1 )>";
function getParts(pattern, values) {
var result = {}, value, p1, p2 = 0;
(pattern.match(/[^{}]+/g) || []).forEach((s, i, a) => {
if (i % 2) return Object.assign(result, { [s]: value });
p1 = values.indexOf(s, p2),
p2 = values.indexOf(a[i + 2], p1);
value = values.slice(p1 + s.length, p2 === -1 ? undefined : p2);
});
return result;
}
var description = "<DP_A>.<Del.Dce Lks.{Link}>.<Pl.Rrs Bk 0.310-PT-304_({strm})>{last}",
title = "<DP_A>.<Del.Dce Lks.abcdef>.<Pl.Rrs Bk 0.310-PT-304_(ghijklΓΆΓΆΓΆΓΆ)>fubar";
console.log(getParts(description, title));
With a for statement and reusing known positions.
function getParts(pattern, values) {
var parts = pattern.match(/[^{}]+/g),
result = {}, p1, p2, i;
if (!parts || parts.length < 2) return {};
p1 = values.indexOf(parts[0]);
for (i = 1; i < parts.length; i += 2) {
p2 = values.indexOf(parts[i + 1], p1);
Object.assign(result, { [parts[i]]: values.slice(p1 + parts[i - 1].length, p2 === -1 ? undefined : p2) });
p1 = p2;
}
return result;
}
var description = "<DP_A>.<Del.Dce Lks.{Link}>.<Pl.Rrs Bk 0.310-PT-304_({strm})>{last}",
title = "<DP_A>.<Del.Dce Lks.abcdef>.<Pl.Rrs Bk 0.310-PT-304_(ghijklΓΆΓΆΓΆΓΆ)>fubar";
console.log(getParts(description, title));
Use replace:
var description = "<DP_A>.<Del.Dce Lks.{Link}>.<Pl.Rrs Bk 0.310-PT-304_({strm})>"
const obj = {
Link: 1,
strm: 2
};
const res = description.replace(/{(.*?)}/g, m => obj[m.slice(1, -1)]);
document.write(res);
Okay, this is far more complex than I actually expected.
I'm not actually that good at this kind of operations, but here is a "working" solution: you may want to rewrite it a bit, but still, the concept is actually fair to me.
The steps followed to achieve the results are:
Acquire all the indexes of "{". I've used a function generator below, but you may use whathever other criteria you want. The goal is to acquire the starting bracket of each match.
loop each matched bracket, look for the closing bracket and acquire the character just after it in the description string.
perform the value match upon the Title string.
Continue by applying currently matched values to update the offsets.
Map the result to collect the desired output: I've intentionally returned an array of items because a placeholder may exist twice.
Some side notes:
The below script, as mentioned above, won't take care of limit cases like "{hello{world}".
The below script can be improved by matching both the previous character and the next character.
The below script might fail in some situations, it just happens to work in this case, but I didn't test it with limit cases.
var description = "<DP_A>.<Del.Dce Lks.{Link}>.<Pl.Rrs Bk 0.310-PT-304_({strm})>";
var Title = "<DP_A>.<Del.Dce Lks.1>.<Pl.Rrs Bk 0.310-PT-304_(1)>";
// Acquire all the indexes of every "{".
// BEWARE: This will actually fail if the description is "&LT{LLT{hello}", but you may change this.
const descriptionLookupIndexes = [].concat(...(function*(){
for (var i = 0; i < description.length; i++) {
if (description[i] === "{") yield [i];
}
})());
let matches = [];
descriptionLookupIndexes.forEach((i, index) => {
// acquire the description by replacing the currently known values.
let _replacedDescription = description;
let _replacedDescriptionIndex = i - matches.reduce((a,b) => a + b.amount, 0);
// This foreach will replace the placeholders already found with their respective values.
matches.forEach(k => {
let splitted = _replacedDescription.split('');
splitted.splice(k.from, k.amount, [k.value.split('')]);
_replacedDescription = splitted.join('');
});
// Acquire the relevant portion of the string.
const needle = _replacedDescription.substring(_replacedDescriptionIndex, _replacedDescription.length);
// Look for the next character after the first } occurrence in the current substring.
const nextChar = needle[needle.indexOf("}") + 1];
// Acquire the relevant substring for the title.
const titleNeedle = Title.substring(_replacedDescriptionIndex, Title.length);
matches.push({
from: _replacedDescriptionIndex,
amount: needle.match(/[^{\}]+(?=})/g)[0].length + 1,
needle: needle.match(/[^{\}]+(?=})/g)[0],
value: titleNeedle.substring(0, titleNeedle.indexOf(nextChar))
});
});
// Matches is now the array with all the occurrences, let's just map it to acquire a new array of objects with the desired format.
// BEWARE: If multiple keys exists, they will be mapped to an array.
const res = matches.reduce((acc, next) => {
acc[next.needle] = acc[next.needle] || [];
acc[next.needle].push({
[next.needle]: next.value
});
return acc;
}, {});
console.log(res);

Splitting a string into multiple lines in javascript

I'm trying to find a way to split long strings to multiple lines so what I'm doing is insert text into an image and if it gets too long it overflows, newlines work but it wouldn't be best idea to let user add the newlines and split it in code, so if i give it a limit it checks if its over limit split to two lines or i mean a newline \n between it, however that's easy but my problem is when it comes that the second part is also over the limit then it should split it in to 3 newlines, how would you go implement that?
Examples
split("sometext", 5); // somet\next
split("Hello", 2); // he\nll\no
Very straightforward answer to your question:
function customSplit(str, maxLength){
if(str.length <= maxLength)
return str;
var reg = new RegExp(".{1," + maxLength + "}","g");
var parts = str.match(reg);
return parts.join('\n');
}
You need a function like the following:
function split(str, maxWidth) {
const newLineStr = "\n";
done = false;
res = '';
do {
found = false;
// Inserts new line at first whitespace of the line
for (i = maxWidth - 1; i >= 0; i--) {
if (testWhite(str.charAt(i))) {
res = res + [str.slice(0, i), newLineStr].join('');
str = str.slice(i + 1);
found = true;
break;
}
}
// Inserts new line at maxWidth position, the word is too long to wrap
if (!found) {
res += [str.slice(0, maxWidth), newLineStr].join('');
str = str.slice(maxWidth);
}
if (str.length < maxWidth)
done = true;
} while (!done);
return res + str;
}
function testWhite(x) {
const white = new RegExp(/^\s$/);
return white.test(x.charAt(0));
};
console.log(split("sometext", 5));
console.log(split("Hello", 2));
https://j11y.io/snippets/wordwrap-for-javascript/
Wraps using specified limit on characters. :)
What kind of interface are you building? If it's a web interface, you should style the string on the front end, instead of modifying it on the data layer.
If it's a text based interface and you really need to do this, then you can get the first n characters while there is a non-empty string, then join with '\n'. Assuming you have underscore:
function split(str, n) {
let numberOfSegments = Math.ceil(_.size(str) / n);
let segments = _.map(_.range(numberOfSegments),
segmentIndex => str.substr(segmentIndex * n, n));
return segments.join('\n');
}

Recursive parser using split in javascript

I have an algorithm where the user will enter a string and I will parse it into an array of 2+ dimensions. So, for example, the user can enter 1,2,3;4,5,6 and set the text to be parsed by the semicolon and the comma. The first pass through will create an array with 2 entries. The second pass through will create a 3 entry array in both prior spots.
The user can add or remove the number of text items to be used to parse the original string such as the semicolon or comma, meaning the resulting array can have as many dimensions as parsing items.
This doesn't seem like a difficult problem, but I have run into some snags.
Here is my code so far.
vm.parsers = [';', ','];
vm.inputString = "1,2,3,4,5;6,7,8,9,10";
function parseDatasetText( )
{
vm.real = vm.parseMe( vm.inputString, 0);
};
function parseMe( itemToParse, indexToParse )
{
if ( indexToParse < vm.parsers.length )
{
console.log('Parsing *'+itemToParse+'* with '+vm.parsers[indexToParse]);
var tempResults = itemToParse.split( vm.parsers[indexToParse] );
for (var a=0; a<tempResults.length; a++)
{
console.log('Pushing '+tempResults[a]);
tempResults[a] = vm.parseMe( tempResults[a], parseInt( indexToParse ) + 1 )
console.log('This value is '+tempResults[a]);
}
}else
{
console.log('Returning '+itemToParse);
return itemToParse
}
};
As you can see from the console logs, the algorithm spits out an undefined after the last parse, and the final answer is undefined.
Maybe I just haven't slept enough, but I was thinking that the array would recursively populate via the splits?
Thanks
function parseDatasetText(){
//composing parser from right to left into a single function
//that applies them from left to right on the data
var fn = vm.parsers.reduceRight(
(nextFn, delimiter) => v => String(v).split(delimiter).map(nextFn),
v => v
);
return fn( vm.inputString );
}
Don't know what else to add.
You can use a simple recursive function like the following (here an example with 3 different delimiters):
function multiSplit(xs, delimiters) {
if (!delimiters.length) return xs;
return xs.split(delimiters[0]).map(x => multiSplit(x, delimiters.slice(1)));
}
data = '1:10,2:20,3:30;4:40,5:50,6:60';
res = multiSplit(data, [';', ',', ':']);
console.log(res)
The following function should suit your requirements, please let me know if not
var parsers = [';', ',', ':'],
inputString = "1:a,2:b,3:c,4:d,5:e;6:f,7:g,8:h,9:i,10:j",
Result = [];
function Split(incoming) {
var temp = null;
for (var i = 0; i < parsers.length; i++)
if (incoming.indexOf(parsers[i]) >= 0) {
temp = incoming.split(parsers[i]);
break;
}
if (temp == null) return incoming;
var outgoing = [];
for (var i = 0; i < temp.length; i++)
outgoing[outgoing.length] = Split(temp[i])
return outgoing;
}
Result = Split(inputString);
try it on https://jsfiddle.net/cgy7nre1/
Edit 1 -
Added another inputString and another set of parsers: https://jsfiddle.net/cgy7nre1/1/
Did you mean this?
var inputString = "1,2,3,4,5;6,7,8,9,10";
var array=inputString.split(';');
for (var i=0;i<array.length;i++){
array[i]=array[i].split(',');
}
console.log(array);

Categories