I am trying to manipulate my URL using URLSearchParams. However URLSearchParams.delete() expects the name of the param. If I have params with the same name, (from what I've tested in chrome) It will delete all params with that name. Is there a way to delete by both name and value?
My query looks something like this:
?color[]=Black&color[]=Green&material[]=Steel
So when I call .delete("color[]") it will remove both color[]= params, but what if I want to only remove a specific one?
The reason for the duplicate names is the backend (PHP) is leveraging this functionallity to auto parse the parameters into arrays...which requires the syntax above.
Big picture is- I'm trying to add/remove "filters" from this array-to-be. Also, some filter categories could have matching values so I don't want remove by value either. I am open to considering an entirely new approach...just trying to do it in the least hacky way.
-- Edit --
For any Laravel users, I recommend not using the index-less syntax. Just use color[0]=, color[1]= etc. I didn't realize laravel supports both syntaxes.
To remove a specific key/value pair, loop over the entries, filter out the unwanted one(s) and create a new URLSearchParams:
function deleteParamsEntry(params, key, value) {
const newEntries = Array.from(params.entries()).filter(
([k, v]) => !(k === key && v === value)
);
return new URLSearchParams(newEntries);
}
const query = "?color[]=Black&color[]=Green&material[]=Steel";
const params = new URLSearchParams(query);
const newParams = deleteParamsEntry(params, "color[]", "Green");
console.log(newParams.toString());
Try this approach:
const deleteURLParamsByNameAndValue = (urlString, paramName, paramValue) => {
const url = new URL(urlString)
const params = url.searchParams
const newParamArray = []
for (var kvPair of params.entries()) {
const k = kvPair[0]
const v = kvPair[1]
if (k!==paramName || v!==paramValue) {
newParamArray.push(kvPair)
}
}
const newSearch = new URLSearchParams(newParamArray)
return decodeURI(`${url.origin}${url.pathname}?${newSearch}`)
}
const urlString = 'https://example.com/path1/path2?color[]=Black&color[]=Green&material[]=Steel'
deleteURLParamsByNameAndValue(urlString,'color[]','Black')
// returns 'https://example.com/path1/path2?color[]=Green&material[]=Steel'
I'm writing a script wherein the user selects directories, which are then stored in an array property, so that they can be recursively crawled.
{
"archives": [
"C:\\AMD\\Packages",
"C:\\Users",
"C:\\Windows",
"D:\\",
"E:\\Pictures\\Birthday"
]
}
I obviously don't want to be storing duplicate paths or paths that are contained by other paths. For example, if the user were to select a new folder to add to the array, E:\\Pictures, then E:\\Pictures\\Birthday would be discarded and replaced by it since E:\\Pictures contains E:\\Pictures\\Birthday.
{
"archives": [
"C:\\AMD\\Packages",
"C:\\Users",
"C:\\Windows",
"D:\\",
"E:\\Pictures"
]
}
I know this can be done by parsing all of the values being considered (i.e. ['C:', 'AMD', 'Packages'], [...], ... etc) and then comparing them all to one another. However, this seems extremely intensive, especially if the array of paths grows bigger and the directory paths are longer.
You could also do it by comparing the strings with includes. For example, if A includes B or B includes A, split them, and discard the one with a longer length.
for (const dir of dirs){
if (newPath.includes(dir) || dir.includes(newPath)){
if (newPath.split('\\') < dir.split('\\')){
// remove dir from json object and replace it with newPath
}
} else {
pathArray.push(dir)
}
}
After reading one of the answers below, I just realized that the includes method runs into the issue of comparing similar, yet unique paths i.e. C:\Users and C:\User.
Although there's gotta be a better way to do this??
This function will give you your desired results. It first looks to see if the parent of the path exists in the archives, and if so, does nothing. If it doesn't, it then removes any children of the path and then inserts the new path.
Update
I've added a delim input to the function to make it usable for unix/MacOS style filenames as well.
let data = {
"archives": [
"C:\\AMD\\Packages",
"C:\\Users",
"C:\\Windows",
"D:\\",
"E:\\Pictures"
]
};
const add_to_archives = (path, data, delim) => {
// does the parent of this path already exist? if so, nothing to do
if (data.archives.reduce((c, v) =>
c || path.indexOf(v.slice(-1) == delim ? v : (v + delim)) === 0, false)) return data;
// not found. remove any children of this path
data.archives = data.archives.filter(v => v.indexOf(path.slice(-1) == delim ? path : (path + delim)) !== 0);
// and add the new path
data.archives.push(path);
return data;
}
add_to_archives("E:\\Pictures\\Too", data, "\\");
console.log(data);
add_to_archives("E:\\PicturesToo", data, "\\");
console.log(data);
add_to_archives("D:\\Documents", data, "\\");
console.log(data);
add_to_archives("C:\\AMD", data, "\\");
console.log(data);
data = {
"archives": [
"/var/www/html/site",
"/etc",
"/usr/tim",
"/bin"
]
};
add_to_archives("/var/www/html/site2", data, "/");
console.log(data);
add_to_archives("/etc/conf.d", data, "/");
console.log(data);
add_to_archives("/usr", data, "/");
console.log(data);
add_to_archives("/var/www/html", data, "/");
console.log(data);
.as-console-wrapper {
max-height: 100% !important;
}
We can approach the problem by using a prefix tree
The purpose is to limit the number of paths we check for inclusion or "containment".
That approach may be useful if you have a lot of siblings (tree traversal + lookup as key for each folder).
It is overkill if you often have a root folder specified in archives
algorithm
tree = {}
foreach path
split the path in folders (one may iterate with substring but it is worth it?)
try to match folders of that path while traversing the tree
if you encounter a stop node, skip to next path
if not,
if your path end on an existing node
mark that node as a stop node
drop the children of that node (you can let them be, though)
else
include the remaining folders of the path as node in tree
mark the last node as a stop node
Implem
Note that implem below will fail if path includes a folder named "stop". By subjective order of preference
Use Map and Symbol('stop')
or a real tree (at least do not store folders alongside the boolean stop)
do not suppose any stop node and always drop children if you manage to reach the end of your path
Hope no one tries to outsmart you and rename stop as some obscure -folder will not exist- lolol_xxzz9_stop
function nodupes(archives){
tree = {};
archives.forEach(arch=>{
const folders = arch.split('\\');
folders.splice(1,1);
//case of empty string such as D:\\\
if(folders[folders.length-1].length==0){folders.pop();}
let cur = tree;
let dropped = false;
let lastFolderIndex = 0;
let ok = folders.every((folder,i)=>{
if(cur[folder]){
if(cur[folder].stop){
dropped = true;
return false;
}
cur = cur[folder];
return true;
}
cur[folder] = {}
cur = cur[folder];
lastFolderIndex = i;
return true;
});
if(ok){
cur.stop = true;
//delete (facultatively) the subfolders
if(lastFolderIndex < folders.length-1){
console.log('cleanup', folders, 'on node', cur)
Object.keys(cur).forEach(k=>{
if(k != 'stop'){
delete cur[k];
}
})
}
}
});
//console.log('tree', JSON.stringify(tree,null,1));
//dfs on the tree to get all the paths to... the leaves
let dfs = function(tree,paths,p){
if(tree.stop){
return paths.push(p.join('\\\\'));
}
Object.keys(tree).forEach(k=>{
dfs(tree[k], paths, p.concat(k));
});
}
let paths = [];
dfs(tree, paths,[]);
return paths;
}
let archives = [
'C:\\\\ab',
'D:\\\\', //just some root
'D:\\\\ab',//be dropped
'D:\\\\abc',//dropped as well
'F:\\\\abc\\\\e',//two folder creation
'C:\\\\ab\\c',
'B:\\\\ab\\c',
'B:\\\\ab',//expect B\\\\ab\\c to be dropped
]
console.log(nodupes(archives))
Try this
console.log([
"C:\\AMD\\Packages",
"C:\\Users",
"C:\\User",
"E:\\Pictures",
"E:\\Pictures\\Birthday",
"C:\\Windows",
"D:\\",
"D:\\aabbcc",
"E:\\Pictures\\Birthday"
].sort().reduce(
(acc, cur) =>
acc.length > 0
&& cur.startsWith(acc[acc.length - 1])
&& ( cur.indexOf("\\", acc[acc.length - 1].replace(/\\$/,"").length) !== -1 )
&& acc || acc.concat(cur)
, []
))
I'm trying to use a regular expression to filter the name column in a csv file that has be put into an object array. Everything works fine if I type the exact value.
values I want "king" to match are below:
kingkong, king kong, king-kong, king_kong, king11, kongking, kong-king, kong_king, kong king, 11king
I've tried using filter and find methods but I want to use filter to return multiple values if they exist. I have tried the following regex but can't figure out the proper sytax if it is even correct.
const CSVToJSON = require('csvtojson');
const user = "king";
CSVToJSON().fromFile("./locations.csv").then(source => {
var found = source.filter(function(v, i){
return ((v["name"]== /\bking.*/g));
})
You can use the following approach.
const CSVToJSON = require('csvtojson');
CSVToJSON().fromFile("./locations.csv").then(source => {
var found = source.filter(function(v, i){
return ((v["name"].match(/king/g)));
});
return statement could be something like
return ((/king/g).test(v["name"]));
OR
return ((v["name"].match(/king/g)));
Both should work
However, your sample patterns show that king might stand either at the beginning or at the end of the target (bot can't have both prefix and suffix). If I am right, that means you don't need regex for that.
const CSVToJSON = require('csvtojson');
const user = "king";
CSVToJSON().fromFile("./locations.csv").then(source => {
var found = source.filter((v, i) => v.startsWith(user) || v.endsWith(user))
/*rest of the code */
});
If king can stand anywhere, you can simply use includes instead.
This is what worked, I'm totally new to JavaScript:
const user = args;
var regex = new RegExp(user, "g");
CSVToJSON().fromFile("./locations.csv").then(source => {
var found = source.filter(function(v, i){
return ((v["name"].match(regex)));
})
I want to replace a particular line using javascript with new content.
This is the file content,
SERVER=1055#localhost
GROUP_SERVERS=2325#localhost
LINE_IAM_INTERESTED=KTYUIERVW:2800
FILE_PATH="C:\Program Files\somefile\Shared Files\"
In this line, LINE_IAM_INTERESTED=KTYUIERVW:2800 .I want to replace KTYUIERVW with KJHTERDY and 2800 with 78945
I have shown what I tried using fs appendfilesync
fs.appendFileSync('file_name').toString().split('\n').forEach(function(line){
app.console.log("called append");
var sEntry = line.split("=");
if (sEntry.length == 2) {
if (sEntry[0] == "LINE_IAM_INTERESTED") {
app.console.log("found one!!!!");
}
}
});
you can try READ -> REPLACE -> WRITE flow:
fs.writeFileSync('file_name', fs.readFileSync('file_name').replace('KTYUIERVW:2800', 'KJHTERDY:78945'))
appendFile and appendFileSync are used for adding to the end of the file. Although you can do it as a one liner as shown in the other answer, I've kept the structure of your code the same. Here you want to read the data, modify it then re-write it. Using the block of code you have, you can modify it to use readFileSync and writeFileSync.
let newData = fs.readFileSync('file_name', 'utf-8').split('\n').map(line => {
let sEntry = line.split('=')
if (sEntry.length == 2) {
if (sEntry[0] == "LINE_IAM_INTERESTED") {
console.log("found one!!!!");
return sEntry[0] + '=' + 'KJHTERDY:78945'
}
}
return line
}).join('\n')
fs.writeFileSync('file_name', newData)
I've swapped the forEach for map which lets us change the array data by returning the desired value. The new array is then joined back together and written back to the file.
const fs = require('fs')
const jsdocFinder = /\/\*\*\n(.+?)\*\//gs
/**
* Convert JSDocs from a file into JSON.
* #function
* #param {String[]|String} dirs The directory or directories of the file(s) to convert.
*/
function interpret (dirs = []) {
if (typeof dir === 'string') dirs = [dirs]
const types = {}
for (const dir of dirs) {
const file = fs.readFileSync(dir, 'utf8')
const docs = jsdocFinder.exec(file)
console.log(docs)
}
return types
}
module.exports = interpret
This is my code for a function that's supposed to convert JSDocs to JSON data. In the for loop, I use a regex to capture any text in between /**\n and */. Unfortunately, it doesn't seem to be working on the files. I have logged what file equals and it should match. I have tested the Regex and it should work fine.
https://i.imgur.com/2FlmeBq.png
docs just equals null every time.
I figured out, since Windows uses CR LF, I need to do \r\n.