Search Placeholder Values in 2 strings - javascript

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);

Related

Grab substring after and before two specific characters in javascript

i have a url search key like that:
?retailerKey=A and i want to grab the retailerKey substring. All examples that i saw are having as example how to take before the char with the indexOf example. How can i implement this to have this substring from the string ?retailerKey=A
You could split() the string on any ? or = and take the middle item ([1]) from the outcome array.
const data = "?retailerKey=A";
const result = data.split(/[\?=]/)[1];
console.log(result);
If you have multiple params, creating an object fromEntries() would be interesting.
const data = "?retailerKey=A?otherKey=B";
const keyVals = data.split(/[\?=]/).filter(x => x); // keys and values
const result = Object.fromEntries(keyVals.reduce((acc, val, i) => {
// create entries
const chunkI = Math.floor(i / 2);
if (!acc[chunkI]) acc[chunkI] = [];
acc[chunkI].push(val);
return acc;
}, []));
console.log(result);
use regex expression.
Following will return the value between character ? and =
var result = "?retailerKey=A".match(/\?(.*)\=/).pop();
console.log(result);
If you would like to always get the string between your query sign and equal sign ?ThisString=
then you can simply use indexOf for example
str.slice(str.indexOf('?')+1,str.indexOf('='))
Using library could be a better choice but to do it from scratch : I suggest to use split with a regular expression.
// split for char equals to ? or & or =;
const url = '/toto?titi=1&tata=2';
const args = url.split(/[\?\&\=]/);
// shift the first element of the list since it the base url before "?"
args.shift();
// detect malformed url
if (args.length % 2) {
console.error('malformed url', args);
}
const dictArgs = {};
for (let i = 0; i < args.length /2; i ++) {
const key = args[2*i];
const val = args[2*i+1];
dictArgs[key] = val;
}
console.log(dictArgs);

Replace element in Array from condition in another array

I'm using Javascript to replace elements in an array from a condition in another array.
I also need the final output to have the "" removed from any element which is replaced.
I have an array, tagArray which generates parts of speech for a given sentence theSentenceToCheck and it looks like this.
tagArray DET,ADJ,NOUN,VERB,ADP,DET,ADJ, NOUN ,ADP,DET,ADJ,NOUN
theSentenceToCheck The red book is in the brown shelf in a red house
I was able to write something that works and generates the desired output but its kinda redundant and total spaghetti.
I've looked at similar questions and tried other approaches using filter, map without success, especially on how to use those approaches and remove the "" for replaced elements.
This is my approach
var grammarPart1 = "NOUN";
var grammarPart2 = "ADJ";
var posToReplace = 0;
function assignTargetToFillIn(){
var theSentenceToCheckArrayed = theSentenceToCheck.split(" ");
var results = [];
var idx = tagArray.indexOf(grammarPart1);
var idx2 = tagArray.indexOf(grammarPart2);
while (idx != -1 || idx2 != -1) {
results.push(idx);
results.push(idx2)
idx = tagArray.indexOf(grammarPart1, idx + 1);
idx2 = tagArray.indexOf(grammarPart2, idx2 + 1);
posToReplace = results;
}
const iterator = posToReplace.values();
for (const value of iterator) {
theSentenceToCheckArrayed[value] ="xtargetx";
}
var addDoubleQuotesToElements = "\"" + theSentenceToCheckArrayed.join("\",\"") + "\"";
var addDoubleQuotesToElementsArray = addDoubleQuotesToElements.split(",");
/**This is where I remove the "" from element replaced with xtargetx*/
const iterator2 = posToReplace.values();
for (const value of iterator2) {
addDoubleQuotesToElementsArray[value] ="xtargetx";
console.log(value);
}
return results;
}
This gives me the desired output
"The",xtargetx,xtargetx,"is","in","the",xtargetx,xtargetx,"in","a",xtargetx,xtargetx
I was wondering what would be a more elegant solution or pointers on which other JS functions to look into.
A more idiomatically correct way to do this leveraging array methods might be like this.
Array.split(" ") splits a sentance into words
Array.filter(word => word.length) removes any value whose length is zero
Array.map((word, index) => {...}) iterates over the array and allows you to keep track of the current index value
Array.includes(element) simply tests that the array includes the value
Array.join(' ') does the opposite of Array.split(' ')
const tagArray = ["DET", "ADJ", "NOUN", "VERB", "ADP", "DET", "ADJ", "NOUN", "ADP", "DET", "ADJ", "NOUN"];
// Split on spaces and remove any zero-length element (produced by two spaces in a row)
const sentanceToCheck = "The red book is in the brown shelf in a red house".split(" ").filter(word => word.length);
const replaceTokens = ["ADJ", "NOUN"];
const replacementWord = "XXX";
const maskedSentance = sentanceToCheck.map((word, index) => {
const thisTag = tagArray[index];
if ( replaceTokens.includes(thisTag) ) {
return replacementWord;
} else {
return word;
}
}).join(' ');
console.log( maskedSentance );

Finding a first letter most repeated in an string

Good evening, I proceed to explain my situation. I started to get interested in javascript which started to dabble
in this language, I have been doing some online courses which I have encountered the following task, basically I am trying through the condition "for" tell me what is the first repeated letter of a string also adding the funsion ".UpperCase () "which at the beginning worked best, until I entered more characters to the string in this case" x "throwing me as output result" undefined "instead of" the most repeated word is: X "reach the case that the string should Consider all the letters regardless of whether they are lowercase or capital letters, for which I ask for help to understand if ¿there is another way? for this task and thus move forward (Sorry for my bad english)
Well i making this task in JavasScript with Atom Editor
var word = "SQSQSQSSaaaassssxxxY";
var contendor = [];
var calc = [];
var mycalc = 0;
function repeat() {
for (var i = 0; i < word.length; i++) {
if (contendor.includes(word[i])) {} else {
contendor.push(word[i])
calc.push(0)
}
}
for (var p = 0; p < word.length; p++) {
for (var l = 0; l < contendor.length; l++) {
if (word[p].toUpperCase() == word[l]) {
calc[l] = calc[l] + 1
}
}
}
for (var f = 0; f < calc.length; f++) {
if (calc[f] > mycalc) {
mycalc = calc[f]
}
}
}
repeat()
console.log("The first letter repeated its: " + contendor[mycalc])
I expected the output of the String to be: "X"
but the actual output is: "Undefined"
The first error in your script is that you store the wrong value in mycalc:
mycalc = calc[f]
Since you want mycalc to be an index, the above should have been
mycalc = f
Now, you will get a result, but your code is actually going through a lot of effort to find the uppercase character that is repeated most often, not first.
Your comparison should have used toUpperCase on both sides of the comparison, otherwise lower case letters will never match.
To get the character that was repeated most often, you could use a Map (to keep track of the counts like you did in calc):
function mostRepeated(str) {
const map = new Map;
let result;
let maxCount = 0;
for (let ch of str) {
ch = ch.toUpperCase();
let count = (map.get(ch) || 0) + 1;
map.set(ch, count);
if (count > maxCount) {
maxCount = count;
result = ch;
}
}
return result;
}
var word = "MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY";
console.log(mostRepeated(word));
Note that you should better use function parameters and local variables. Declaring your variables as global is not considered best practice.
You could find the letter that occurs the most number of times in a string by:
first creating a map that relates each unique letter, to the number of times it occurs in the string
converting that map to an array of "key/value" entries, and then sorting those entries by the "count value"
returning the "letter key" that has the largest count
One way to express this in JavaScript would be via the following:
function findMaxLetter(word) {
/* Create a map that relates letters to the number of times that letter occours */
const letterCounts = Array.from(word).reduce((map, letter) => {
return { ...map, [letter] : (map[letter] === undefined ? 0 : map[letter] + 1) }
}, {})
/* Sort letters by the number of times they occour, as determined in letterCounts map */
const letters = Object.entries(letterCounts).sort(([letter0, count0], [letter1, count1]) => {
return count1 - count0
})
.map(([letter]) => letter)
/* Return letter that occoured the most number of times */
return letters[0]
}
console.log("The first letter repeated its: " + findMaxLetter("MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY"))
I this is solution is most detailed for you
function func( word ){
word = word.toLowerCase();
var i, charCountCache = {};
//store all char counts into an object
for( i = 0; i < word.length; i++){
if( charCountCache[ word[ i ] ] )
charCountCache[ word[ i ] ] = charCountCache[ word[ i ] ] + 1;
else
charCountCache[ word[ i ] ] = 1;
}
//find the max value of char count in cached object
var fieldNames = Object.keys( charCountCache )
, fieldValues = Object.values( charCountCache )
, mostReapeatChar = '', mostReapeatCharCount = 0;
for( i = 0; i < fieldNames.length; i++ ){
if( mostReapeatCharCount < fieldValues[i] ){
mostReapeatCharCount = fieldValues[i];
mostReapeatChar = fieldNames[i];
}
}
console.log('most repeating char: ', mostReapeatChar, ' no of times: ', mostReapeatCharCount )
}
console.log("The first letter repeated its: " + contendor[mycalc])
You tried to print the 14th index of contendor which has only 9 values, that is why your log result was undefined.
You probably wanted to print word[mycalc].
Also if you intended to count x as X, you should have added toUpperCase() to every letter you process/go-through.
This is only a note to the issues in your code, there are better/faster/cleaner solutions to reach the result which i am sure other answers will provide.
my advice would be to create a hashmap such as
letter => [indexLetter1, indexLetter2].
From that hashmap, you could easily find your first repeated letters.
For that string MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY, hashmap will look like
[
M => [0,5,..],
B => [1, ..],
X => [2, ..],
...
]
now you can find every letter with multiple values in its array, then in those arrays take the one with the lowest value.
If you want to get the index of most repeated letter, you can use Array.from to convert the word into an array. Add a map function to make all letters uppercase.
Get the count of each letter by using reduce and Object.entries
Use indexOf to the get the index of the lettet in the array. Please note that indexOf count the letters from 0.
var word = "MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY";
var letters = Array.from(word, o => o.toUpperCase());
var [highestLetter, highestCount]= Object.entries(letters.reduce((c, v) => (c[v] = (c[v] || 0) + 1, c), {})).reduce((c, v) => c[1] > v[1] ? c : v);
var index = letters.indexOf(highestLetter);
console.log("Most repeated letter:", highestLetter);
console.log("Count:", highestCount);
console.log("First Index:", index);

Javascript Regex Custom Replace

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);

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