I have the following array of strings. The names are locations, and each location has 4 integers "attached" to it.
Using regex (in nodeJS, with javascript), I am trying to extract the name of the location, and the last (4th) of the integers for each location.
[ ' UNICENTRO CALI 1131908 296780 133622 968750',
' PASTO 2 1044057 212780 133004 964281',
' CALIMA 1397254 311214 173761 1259801',
' PALMIRA2 922857 272954 103978 753881',
' PEREIRA CRA 6 1188885 157589 165004 1196300',
' DE LA CUESTA-BUCARAMANGA 219916 49526 27261 197651' ]
for example, for the first location I would need to fish out "UNICENTRO CALI" and "968750".
To do this, I've tried:
myArray[i].split(" ")
This separates the name of the location from the four integers, but this will turn into an inefficient mess.
Any chance somebody can do it elegantly with a regular expression?
If you aren't specifically looking for a Regex to parse your entire data, here's one way to do it easily:
var a = [ 'Total C.O. UNICENTRO CALI 1,131,908 296,780 133,622 968,750',
'Total C.O. PLAZA CAICEDO 988,721 272,182 114,641 831,180',
'Total C.O. COSMOCENTRO 692,679 159,488 85,309 618,500',
'Total C.O. PASTO 2 1,044,057 212,780 133,004 964,281'];
var b = [];
a.forEach(function(item){
var splitItem = item.split(/\s\s+/),
len = splitItem.length;
b.push({"name":splitItem[1], "value":splitItem[len-1]});
});
console.log(b);
I used the data from your Regex101 link to demonstrate in this jsFiddle.
This will capture all your columns:
/'\s+(.*\S)?\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)'/
capture group 1 = location
capture group 2 = num 1
capture group 3 = num 2
capture group 4 = num 3
capture group 5 = num 4
var str = "' UNICENTRO CALI 1131908 296780 133622 968750'";
var arr = /'\s+(.*\S)?\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)'/.exec(str);
> console.log(arr)
[Log] Array (6)
0"' UNICENTRO CALI 1131908 296780 133622 968750'"
1"UNICENTRO CALI"
2"1131908"
3"296780"
4"133622"
5"968750"
Array Prototype
Your data changed, use this:
/'(.*\S)\s+([\d,]+)\s+([\d,]+)\s+([\d,]+)\s+([\d,]+)'/
https://regex101.com/r/jJ6xM7/2
Give this a try:
/^'\s+(\w+ +\w*)( +\d+){3} +(\d+)'/
Where $1 (group 1) is your location and $3 (group 3) is the last set of integers on each line.
As I mentioned, your data from the original post changed. Use ergonaut's recommended expression:
/'(.*\S)\s+([\d,]+)\s+([\d,]+)\s+([\d,]+)\s+([\d,]+)'/
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
There is a list of product data. Each product item has a string-type name-property.
How could a viable transformation look like that does convert a product-name into a valid HTML id-attribute value?.
Viable means that a transformation is build in a way that there should be almost no chance for generating identical id's from two different but similar constructed product names.
The naming of common products looks like this ...
"2-inch leg extension"
"2' x 8' Overhead Garage Storage Rack"
"4 Drawer Base Cabinet 16-1/2"W x 35"H x 22-1/2"D"
"24" Long Tool Bar w/ Hooks Accessory"
Transformed validly the above list might look like that ...
"z2-inchlegextension"
"z2x8OverheadGarageStorageRack"
"z4DrawerBaseCabinet16-12Wx35Hx22-12D"
"z24LongToolBarwHooksAccessory"
One could consider providing a prefix (e.g. "z") to the to be generated id in oder to make it a valid HTML id-attribute.
I'm not familiar with replacement techniques that assure results which will be repeatable consistent.
How could a possible transformation approach look like?
You can try this-
const data = [
"2-inch leg extension",
"2' x 8' Overhead Garage Storage Rack",
"4 Drawer Base Cabinet 16-1/2\"W x 35\"H x 22-1/2\"D",
"24\" Long Tool Bar w/ Hooks Accessory"
];
const res = data.map(str => str.replace(/[^a-z\d\-_]/ig, ''));
console.log(res);
If you need any prefix with the ID then add it like-
const prefix = 'Z';
const res = data.map(str => prefix + str.replace(/[^a-z\d\-_]/ig, ''));
The simplest answer that fulfills your requirement:
string.replace(/[^A-Za-z]/g, "");
If there are no letter characters this will result in an empty string. But since IDs need to start with letters anyway, you need special handling for cases where your product names have no letters in them
The following approach creates configurable identifiers.
It also preserves as much information of a given product name as possible in order to prevent the accidental creation of identifier duplicates.
It does so by translating the string patterns of technical measures, units and terms as much as it could be anticipated from the examples provided by the OP.
const productNameList = [
"2-inch leg extension",
"2' x 8' Overhead Garage Storage Rack",
'4 Drawer Base Cabinet 16-1/2"W x 35"H x 22-1/2"D',
'24" Long Tool Bar w/ Hooks Accessory'
];
function createIdentifier(str) {
const config = this;
const prefix = config.prefix || '_';
const separator = config.separator || '';
const id = [prefix, str
// replace foot symbol that follows immediately after a digit
.replace((/([\d])'/g), `$1${ separator }Ft`)
// replace inch symbol (double quote character)
.replace((/"/g), `${ separator }In${ separator }`)
// replace times character enclosed by word boundaries
.replace((/\bx\b/g), 'Times')
// replace digit connector, a minus symbol enclosed by digits
.replace((/([\d])-([\d])/g), `$1${ separator }And${ separator }$2`)
// replace division symbol that is enclosed by digits
.replace((/([\d])\/([\d])/g), `$1${ separator }By${ separator }$2`)
// uppercase any character that follows a word boundary
.replace((/\b([\w])/g), ([$1]) => $1.toUpperCase())
// replace/delete all non word characters.
.replace((/[\W]+/g), separator)
].join('');
return ((separator && id.toLowerCase()) || id);
}
console.log(
productNameList,
' => HTML id attribute => ',
productNameList.map(createIdentifier, { prefix: 'pid_' })
);
console.log(
productNameList,
' => HTML id attribute (long) => ',
productNameList.map(createIdentifier, { prefix: 'pid_', separator: '-' })
);
console.log(
productNameList,
' => valid JS variable name => ',
productNameList.map(createIdentifier)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
updated
I'm quite a new to this. I have looked everywhere and tried everything under the sun to fix this on my own.
My data is from a text input where i need to read specific line. My code reads the lines perfectly using the slice(2,1) method. Now I need to use the data to do other things.
my extracted string from reading data lines from 3rd line data till 2nd last line, and this already works:
var x = readData.slice(2,-1).toString();
Output using console.log(x); //0 1,2 3,4 5 as it should be
but I want: '0,1','2,3','4,5'
So that i can use this data to do other things.
I have tried:
var x = readData.slice(2,-1).toString().split(' ',-1);
this gives me: [ '0', '1,2', '3,4', '5' ] //which is the closest
i have also tried:
var x = readData.slice(2,-1).toString().replace(/\s/g, ', ').split(" ", -1); which gives [ '0,', '1,2,', '3,4,', '5' ]
var x = [x.split(' ').join(',')]; which gives [ '0,1,2,3,4,5' ]
and a few other combos too. Can anyone please help?
According to the following statement
.replace(/\s/g, ', ').split(" ", -1); which gives [ '0,', '1,2,', '3,4,', '5' ]
in the question, this 0 1,2 3,4 5 is a string, so you can split by comma and then map the strings according to the desired output
console.log("0 1,2 3,4 5".split(",").map(s => s.split(/\s+/g).join(",")));
I need to be able to convert a string (IP address) such as this 10.120.0.1 to a string (ISIS Network ID) such as this 49.0001.0101.2000.0001.00. The middle section 010 1.20 00.0 001 corresponds to the first string (I've spaced them out to show the IP address is inside it). You can see that there are 4 digits in each ISIS Network ID hextet that need to correspond to 3 digits in the IP Address octet. A number of 53 for example would have a leading 0 to make 3 digits.
All the IP addresses start with 10.120. so I just need to inject the last 2 octets from the IP Address into the ISIS Network ID.
I need this to be dynamic so when someone types in another ip address into a loopbackIP input, it automatically updates the isisNetworkID field.
I have this:
49.0001.0101.{{ isisNetworkID }}.00
This needs to take the value from an input v-model="loopbackIP" that I have and translate the remaining values to sit in the middle of that isisNetworkID following this format - xxxx.xxxx.
I've got this computed calculation but I'm not sure how to make 4 digits equal 3...
const loopbackIP = '10.120.0.1';
const isisNetworkID = computed(() => {
let idaho = '10.120.';
if (loopbackIP.indexOf(idaho)) {
return loopbackIP.slice(7);
} else {
console.log('Nothing is happening');
}
});
I hope this makes sense...
I think I understand what you're trying to achieve. Let's break it down into digestible parts. You have an IP address of:
10.120.0.1
And you want to transform it such that each part is padded to 3 digits:
['010', '120', '000', '001']
This can be done by splitting the string by the . character, and the using String.prototype.padStart(). We then join the array back into a string:
'010120000001'
||||
^^^^ -> to be deleted
We know that the first 4 digits is not needed, since it's already part of your template, so we can remove them using String.prototype.substring(4). That leaves us with:
'20000001'
Now it is just the matter of splitting it into 4 characters per item:
['2000', '0001']
...and rejoining it with . character:
'2000.0001'
...and interpolating it back into the string. I have a proof-of-concept example below, which should output the desired string:
const loopbackIP = '10.120.0.1';
const parts = loopbackIP.split('.').map(x => x.padStart(3, '0'));
// Remove the first 4 characters
let isisNetworkId = parts.join('');
isisNetworkId = isisNetworkId.substring(4);
const output = `49.0001.0101.${isisNetworkId.match(/.{4}/g).join('.')}.00`;
console.log(output);
So if you want to translate it to your VueJS code, it should look no different that this:
const loopbackIP = '10.120.0.1';
const isisNetworkID = computed(() => {
const loopbackIP = '10.120.0.1';
const parts = loopbackIP.split('.').map(x => x.padStart(3, '0'));
let isisNetworkId = parts.join('');
isisNetworkId = isisNetworkId.substring(4);
// Rejoin, split into items of 4-character long, rejoin by period
return isisNetworkId.match(/.{4}/g).join('.');
});
Example Company 1,company ltd 2,company, Inc.,company Nine nine, ltd,company ew So here is example of the string, I want to split it like that it consider Company 1 as one company and company, Inc. as one, but here got situation in company, Inc. it condidering 2 companies while this logic. how can I resolve this? Lke with such strings company, Inc. I want to consider it one element only
const company = company.split(",");
Here the string can be anything, this is just example for the string, but it can be any name. So I am looking for generic logic which works for any string, having same structure of string.
Note $ ==(,) represents as separation point, kept to get clarity that from that point I need to separate the string
Object:
Example 1
{
_id: 5de4debcccea611e4d14d4d5
companies: One Bros. Inc. & Might Bros. Dist. Corp.$Pages, Inc.$Google Inc. Search$Aphabet Inc. tech.
}
Example 2
{
_id: 5de4debccc333611e4d14d4f5
companies: Google Comp. Inc.$Google Comp. Inc. Estd.$Tree, Ltd.$Tree, Ltd.
}
First I split on 'ompany' rather than 'company', because you have one instance of 'Company' with a capital C -- see the output of the first console log within a comment below.
Then I put things back together using reduce -- map is not the right choice here, as I need an array that is one fewer than the size of the fragments I generated. Then though since I need an array that corresponds to the number of strings we want to return, which is one fewer than the number of fragments, the first thing I do inside my reduce is ensure I do not look beyond the end of the array.
Then I split each fragment and pop off the last element, which just puts either "C" or "c" back together with "ompany". Then I replace any trailing ',c' from the next fragment with an empty string, and add the result to the company. Finally I add the entire result to the array I'm generating with reduce. See comment results at bottom. Also here it is on repl.it: https://repl.it/#dexygen/splitOnCompanyStringLiteral
This is a fairly concise way to do this but again if you can do anything to improve your data, you won't have to use such unnecessarily complicated code.
const companiesStr = "Company 1,company ltd 2,company, Inc.,company Nine nine, ltd,company ew";
const companySuffixFragments = companiesStr.split("ompany");
console.log(companySuffixFragments);
/*
[ 'C', ' 1,c', ' ltd 2,c', ', Inc.,c', ' Nine nine, ltd,c', ' ew' ]
*/
const companiesArr = companySuffixFragments.reduce((companies, fragment, index, origArr) => {
if (index < companySuffixFragments.length - 1) {
let company = fragment.split(',').pop() + 'ompany'
company = company + origArr[index + 1].replace(/,c$/, '');
companies.push(company);
}
return companies
}, []);
console.log(companiesArr);
/*
[ 'Company 1',
'company ltd 2',
'company, Inc.',
'company Nine nine, ltd',
'company ew' ]
*/
First change , with any other symbol. I am using & here and then split string with ,
var str= 'Company 1,company ltd 2,company, Inc.,company Nine nine, ltd,company ew';
str = str.replace(', Inc.','& Inc.');
/*str = str.replace(', ltd','& ltd');*/
console.log(str.split(',').map((e)=>{return e.replace('&',',').trim()}));
try with the below solution.
var str = ["company 1","company ltd 2","company", "Inc.","company Nine nine", "ltd","company ews"];
var str2 =str.toString()
var str3 = str2.split("company")
function myFunction(item, index,arr){if(item !=""){let var2 = item.replace(/,/g," ");var2 = "Company"+var2;arr[index]=var2;} }
str3.forEach(myFunction)
OUtput:
str3
(6) ["", "Company 1 ", "Company ltd 2 ", "Company Inc. ", "Company Nine nine ltd ", "Company ews"]
And remove the first element of the array.
As has been commented I'd try to get a more clean String so that you don't have to write "strange" code to get what you need.
If you can't do that right now this code should solve your problem:
let string = 'Company 1,company ltd 2,company, Inc.,company Nine nine, ltd,company
ew';
let array = string.split(',');
const filterFnc = (array) => {
let newArr = [],
i = 0;
for(i = 0; i < array.length; i++) {
if(array[i].toLowerCase().indexOf('company') !== -1) {
newArr.push(array[i]);
} else {
newArr.splice(newArr.length - 1, 1, `${array[i - 1]}, ${array[i]}`);
}
}
return newArr;
};
let filteredArray = filterFnc(array);
I'm trying to mask a portion of a string using JavaScript.
e.g. Mask second and third segment of credit-card number like this using regex:
4567 6365 7987 3783 → 4567 **** **** 3783
3457 732837 82372 → 3457 ****** 82372
I just want to keep the first 4 numbers and the last 5 characters.
This is my first attempt: /(?!^.*)[^a-zA-Z\s](?=.{5})/g
https://regex101.com/r/ZBi54c/2
You can try this:
var cardnumber = '4567 6365 7987 3783';
var first4 = cardnumber.substring(0, 4);
var last5 = cardnumber.substring(cardnumber.length - 5);
mask = cardnumber.substring(4, cardnumber.length - 5).replace(/\d/g,"*");
console.log(first4 + mask + last5);
You could slice the first four digits and apply a replacement for the rest.
console.log(
['4567 6365 7987 3783', '3457 732837 82372'].map(
s => s.slice(0, 4) + s.slice(4).replace(/\d(?=.* )/g, '*')
)
);
The answer apparently satisfies the OP. Here is another solution using only Regexes:
function starry(match, gr1, gr2, gr3) {
var stars = gr2.replace(/\d/g, '*');
return gr1 + " " + stars + " " + gr3;
}
function ccStarry(str) {
var rex = /(\d{4})\s(\d{4}\s\d{4}|\d{6})\s(\d{4}|\d{5})/;
if (rex.test(str))
return str.replace(rex, starry);
else return "";
}
var s1 = "4567 6365 7987 3783";
var s2 = "3457 732837 82372";
var s3 = "dfdfdf";
console.log(ccStarry(s1));
console.log(ccStarry(s2));
console.log(ccStarry(s3));
This ensures that the pattern matches before trying any replacements. For example, in the third test case, it returns an empty string. The pattern can be updated to match other credit card patterns besides the ones given in the question.
I would like to elaborate more on the answer from #Nina Scholz, I use .slice() in the following sample code for masking the variable in 2 condition.
Just a simple variable var n = '12345567890'
Array object
// Single number
var n = '601115558888';
var singleNumber = n.slice(0, 4) + n.slice(4, n.length -4).replace(/\d/g,'*') + n.slice(n.length -4);
console.log(singleNumber);
// array of object
var obj = [{
contacts_name: 'Jason',
contacts_num : '651231239991'
},
{
contacts_name: 'King',
contacts_num : '60101233321'
}];
// Mask for the middle number, showing the first4 number and last4 number
// and replace the rest number with *
var num = obj.map((element, index) =>
element.contacts_num.slice(0,4)
+ element.contacts_num.slice(4, element.contacts_num.length-4).replace(/\d/g, '*')
+ element.contacts_num.slice(element.contacts_num.length -4)
);
console.log(num);
If it's JavaScript doing the regex masking, you've already failed because JS should never need to know the original card number, except when you've just received it from the user and are sending it to the server for the first time, in which case you shouldn't be masking it anyway so the user can check for typos.
I can't really help you there, you've already failed in the worst way.
Server-side, if the number is already broken into spaces*, then one option is: (in PHP but the same idea applies to all)
$parts = explode(" ",$fullnumber);
$first = array_shift($parts);
$last = array_pop($parts);
$middle = implode(" ",$parts);
$mask = preg_replace("/\d/","*",$middle);
$result = "$first $mask $last";
* it shouldn't be