how to substring in javascript but excluding symbols - javascript

I need to use (substring method) in my javascript web network project, but excluding : colon symbol, because it is hexadecimal ip address, and I don't want to accept : colons as a string or lets say number in the substring, I want to ignore it. How to do that?
This is the example IPV6 in the input field:
2001:2eb8:0dc1:54ed:0000:0000:0000:0f31
after substring from 1 to 12:
001:2eb8:0d
as you can see it accepted colons also, but in fact, I need this result:
2001:2eb8:0dc1
so by excluding these two symbols, it would have gave me that result above, but I don't know how.
and here is the code, IpAddressInput, is only a normal input field which I write the ip address in it.
Here is the code:
var IpValue = $('#IpAddressInput').val();
alert(IpValue.substr(1, (12) -1));

Answer 1: I think there is no direct function to results like you want but this answer will help you. I counted the number of colons from index 0 to 12 and then slice the source string from 0 to 12 plus the number. Here is the code:
let val = "2001:2eb8:0dc1:54ed:0000:0000:0000:0f31";
let numOfColons = val.slice(0, 12).match(/:/g).length;
let result = val.slice(0, 12 + numOfColons);
console.log(result)
Answer 2: If you are sure that there is a colon after exactly every 4 characters, a better solution will be this. The idea is to remove all colons from the string, slice from index 0 to 12, and add a colon after every 4 characters. Finally, it removes the last colon. Here is the code:
let value = "2001:2eb8:0dc1:54ed:0000:0000:0000:0f31";
let valueExcludeColon = value.replace(/:/g, ''); // '20012eb80dc154ed0000000000000f31'
let result = valueExcludeColon.slice(0,12).replace(/(.{4})/g, "$1:"); // '2001:2eb8:0dc1:'
let finalResult = result.slice(0, -1); // 2001:2eb8:0dc1
console.log(finalResult)

Related

Split Number every nth position from the last

I have a number like this.
const number = 123456789;
I'd like to split it like [1, 2345, 6789] or ['1','2345','6789'];
I've found match() with Regex.
console.log(number.toString().match(/.{1,4}/g));
It returns ['1234', '5678', '9']
It looks pretty well done, but It's a reversed result that I want.
so, I made a tricky flow for this.
console.log(number.toString().split('').reverse().join('').match(/.{1,4}/g));
So, Now I get ['9876','5432','1']
But it doesn't still being what I want.
console.log(
number.toString().split('').reverse().join('').match(/.{1,4}/g).map(str=>str.split('').reverse().join('')).reverse());
Finally, I can get the result that I want.
But It looks pretty ugly and inefficient.
Even I think it shouldn't be used on the code.
So, my question is How can I split a number every nth position efficiently?
If you want to make the code shorter, match 1 to 4 characters while using negative lookahead for 0 or more groups of .{4}, followed by $ (the end of the string):
const number = 123456789;
console.log(
number.toString().match(/.{1,4}(?=(?:.{4})*$)/g)
);
But this requires, on every match, checking the number of characters from the match to the end of the string, which is an O(n ^ 2) process overall. To be more efficient, check the length of the string first, and use modulo to take as many characters as needed to make the remaining string have a length of a multiple of 4:
const str = String(123456789);
const index = str.length % 4;
const firstItem = str.slice(0, index);
const items = str.slice(index).match(/\d{4}/g);
items.unshift(firstItem);
console.log(items);
This code is longer, but it runs in O(n).
You could match by groups from 1 to 4 characters and take look forward to a group of four.
var number = 123456789,
parts = number.toString().match(/.{1,4}(?=(.{4})*$)/g);
console.log(parts);
To avoid splitting and reversing, another option might be to left-pad the number string until it is a multiple of the group size, match and trim back again:
>>> s.padStart(s.length + (4 - s.length % 4)).match(/(.{4})/g).map(s => s.trim())
[ '1', '2345', '6789' ]

Regex in javascript, trying to match but doesn't seem to work with $

EDIT: This question is DIFFERENT. The regex works fine that everyone sent me. The problem is that the $ sign DOESN'T WORK on my string, but it works on others. I can't figure out why and I posted my function below.
I need to find a number at the end of a string, it will be like thisL
My Goal Amount: $25.00/$100.00.
I've tried
var matches = fileDataResult.match(/\d+$/);
but it returns null, I tried it without the $ and it returns the 25, without the .00.
How can I get a variable as a number for the first ones (25.00, with the decimals) and a different variable for the 100.00, with the decimals as well. I need the variables seperate so I can work on them, but I think regex is broken because it won't even work with the $ sign... anyone have suggestion? This is in javascript.
edit:
here is my function, it reads a .txt file and gets the string. I can console.log the string just fine and it work, but it won't work when I use $ in regex!
function fileReaderFunc(file) {
const fileReader = new FileReader();
fileReader.onload = function() {
let fileDataResult = '';
const fileData = fileReader.result;
fileDataResult = fileData.toString();
console.log(fileDataResult);
let str = fileDataResult;
let reg = /\d+(\.\d+)?$/g;
console.log(str.match(reg));
};
fileReader.readAsText(file);
}
let str = "My Goal Amount: $25.00/$100.00.";
str = str.substring(-1,str.length-1); // remove the terminal period
let reg = /\$.+\$.+$/g;
let res = str.match(reg);
let arr = res[0].split('/');
let [num1,num2] = arr;
console.log("1st: ", num1.substring(1, num1.length));
console.log("2nd: ", num2.substring(1, num2.length));
As it turns out this regex is simpler than one might suppose since the text itself includes dollar signs. One can construct a regex that searches for a literal dollar sign followed by other characters and then a second literal dollar sign also followed by other characters from the end of the string marked by a dollar sign symbol minus any slash which signifies the end of a string.
The match is stored in a result array containing one element whose string value is then split on the literal slash mark. The results are then stored in an array arr. Then the values stored in the array are assigned to variables num1 and num2 through array destructuring.
If you prefer a more focused regex, you can also code as follows:
let s = "My Goal Amount: $25.00/$100.00.";
s = s.substring(-1, s.length - 1);
let reg = /\$\d+\.\d+.\$\d+\.\d+$/;
let replaced = s.match(reg)[0].replace(/\$/g, "");
console.log(replaced.split("/"));
If you neglect to trim the string s of the terminal period, then the regex will not match with the string which results in a null. This regex specifies a pattern at the end of the string that starts with a dollar sign,followed by one or more digits then a period and one or more digits. The pattern continues with matching another character (in this case the slash mark) and then a dollar sign followed by one or more digits, next a period and again one or more digits.
First of all \d+ do not match .
You can use this
\d+(\.\d+)?$
Explanation
\d+ - Matches one or more digits.
(\.\d+)? Matches . followed by one or more digit. (? makes it optional )
let str = "abc 125.00";
let reg = /\d+(\.\d+)?$/g;
console.log(str.match(reg))

RegEx - prefix + input value

I have input and I would like to achieve to always have in value prefix +34 and value typed by user which consist of 9 digits
I have tried somethign like this
let val = value.replace(/[^\d]{9}/g, "+34{1}");
but it does not work, any idea what I am doing wrong ??
Simple string concatenation is enough for this.
let val = '+34' + value;
In your current code, it's actually removing entire 9 digits with the string
("+34{1}"). To refer the match in replace string you can use $& in that.
let val = value.replace(/^\d{9}/, "+34$&");
Or alternatively use positive look-ahead in the regex to assert the position where you want to insert.
let val = value.replace(/^(?=\d{9})/, "+34");

Extracting substring from string based on delimiter

I am trying to extract the data out of an encoded 2D barcode. The extraction part is working fine, and I can get the value in a text input.
E.g., the decoded string is
]d20105000456013482172012001000001/:210000000001
Based on the following rules (couldn't get the proper table markdown thus attaching a picture), I am trying to extract the substrings from the string mentioned above.
Substrings I want to extract:
05000456013482 (which is after the delimiter 01)
201200 (which is after delimiter 17)
00001 (which is after delimiter 10)
0000000001 (which is after delimiter 21)
P.S - > the first 3 chars in the original string (]d2) are always the same since it just simply signifies the decoding method.
Now some quirks: 

1) The number of letters after delimiter 10 is not fixed. So, in the above-given example even though it is 00001 it could be even 001. Similarly, the number of letters after delimiter 21 is also not fixed and it could be of varying length.
For different length delimiters, I have added a constant /: to determine when encoding has ended after scanning through a handheld device.
Now, I have a look for /: after delimiter 10 and extract the string until it hits /: or EOL and find delimiter 21 and remove the string until it hits /: or EOL
2) The number of letters after delimiter 01 and 17 are always fixed (14 letter and six letters respectively)

 as shown in the table.
Note: The position of delimiters could change. In order words, the encoded barcode could be written in a different sequence.


]d20105000456013482172012001000001/:210000000001 - Note: No /: sign after 21 group since it is EOL
]d2172012001000001/:210000000001/:0105000456013482 - Note: Both 10 and 21 group have /. sign to signify we have to extract until that sign
]d21000001/:210000000001/:010500045601348217201200 - First two are of varying length, and the next two are of fixed length.
I am not an expert in regex and thus far I only tried using some simple patterns like (01)(\d*)(21)(\d*)(10)(\d*)(17)(\d*)$ which doesn't work in the given an example since it looks for 10 like the first 2 chars. Also, using substring(x, x) method only works in case of a fixed length string when I am aware of which indexes I have to pluck the string.
P.S - Either JS and jQuery help is appreciated.
While you could try to make a very complicated regex to do this, it would be more readable, and maintainable to parse through the string in steps.
Basic steps would be to:
remove the decode method characters (]d2).
Split off the first two characters from the result of step 1.
Use that to choose which method to extract the data
Remove and save that data from the string, goto step 2 repeat until exhausted string.
Now since you have a table of the structure of the AI/data you can make several methods to extract the different forms of data
For instance, since AI: 01, 11, 15, 17 are all fixed length you can just use string's slice method with the length
str.slice(0,14); //for 01
str.slice(0,6); //for 11 15 17
While the variable ones like AI 21, would be something like
var fnc1 = "/:";
var fnc1Index = str.indexOf(fnc1);
str.slice(0,fnc1Index);
Demo
var dataNames = {
'01': 'GTIN',
'10': 'batchNumber',
'11': 'prodDate',
'15': 'bestDate',
'17': 'expireDate',
'21': 'serialNumber'
};
var input = document.querySelector("input");
document.querySelector("button").addEventListener("click",function(){
var str = input.value;
console.log( parseGS1(str) );
});
function parseGS1(str) {
var fnc1 = "/:";
var data = {};
//remove ]d2
str = str.slice(3);
while (str.length) {
//get the AI identifier: 01,10,11 etc
let aiIdent = str.slice(0, 2);
//get the name we want to use for the data object
let dataName = dataNames[aiIdent];
//update the string
str = str.slice(2);
switch (aiIdent) {
case "01":
data[dataName] = str.slice(0, 14);
str = str.slice(14);
break;
case "10":
case "21":
let fnc1Index = str.indexOf(fnc1);
//eol or fnc1 cases
if(fnc1Index==-1){
data[dataName] = str.slice(0);
str = "";
} else {
data[dataName] = str.slice(0, fnc1Index);
str = str.slice(fnc1Index + 2);
}
break;
case "11":
case "15":
case "17":
data[dataName] = str.slice(0, 6);
str = str.slice(6);
break;
default:
console.log("unexpected ident encountered:",aiIndent);
return false;
break;
}
}
return data;
}
<input><button>Parse</button>
Ok, here's my take on this. I created a regex that will match all possible patterns. That way all parts are split correctly, all that remains is to use the first two digits to know what it means.
^\]d2(?:((?:10|21)[a-zA-Z0-9]{1,20}(?:\/:|$))|(01[0-9]{14})|((?:11|15|17)[0-9]{6}))*
I suggest you copy it into regex101.com to read the full descriptors and test it out against different possible results.
There are 3 mains parts:
((?:10|21)[a-zA-Z0-9]{1,20}(?:\/:|$))
Which tests for the sections starting in 10 and 21. It looks for alphanumerical entities between 1 and 20 times. It should end either with EOL or /:
(01[0-9]{14})
Looks up for the GTIN, pretty straightforward.
((?:11|15|17)[0-9]{6})
Looks up for the 3 date fields.
As we expect those 3 segments to come in any order, I've glued them around | to imply a OR and expect this big sequence to repeat (with the * at the end expressing 0 or more, we could define the exact minimum and maximum for more reliability)
I am unsure if this will work for everything as the test strings you gave do not include identifiers inside actual values... It could very well happen that a product's best before date is in January so there will be a 01 in its value. But forcing the regex to execute in this manner should circumvent some of those problems.
EDIT: Capturing groups are only capturing the last occurence, so we need to split their definitions:
^\]d2(?:(21[a-zA-Z0-9]{1,20}(?:\/:|$))|(10[a-zA-Z0-9]{1,20}(?:\/:|$))|(01[0-9]{14})|(11[0-9]{6})|(15[0-9]{6})|(17[0-9]{6}))*
EDIT AGAIN: Javascript seems to cause us some headaches... I am not sure of the correct way to handle it, but here's an example code that could work.
var str = "]d20105000456013482172012001000001/:210000000001";
var r = new RegExp("(21[a-zA-Z0-9]{1,20}(?:\/:|$))|(10[a-zA-Z0-9]{1,20}(?:\/:|$))|(01[0-9]{14})|(11[0-9]{6})|(15[0-9]{6})|(17[0-9]{6})", "g");
var i = 0;
while ((match = r.exec(str)) != null) {
console.log(match[0]);
}
I am not very happy with how it turns out though. There might be better solutions.

getting contents of string between digits

have a regex problem :(
what i would like to do is to find out the contents between two or more numbers.
var string = "90+*-+80-+/*70"
im trying to edit the symbols in between so it only shows up the last symbol and not the ones before it. so trying to get the above variable to be turned into 90+80*70. although this is just an example i have no idea how to do this. the length of the numbers, how many "sets" of numbers and the length of the symbols in between could be anything.
many thanks,
Steve,
The trick is in matching '90+-+' and '80-+/' seperately, and selecting only the number and the last constant.
The expression for finding the a number followed by 1 or more non-numbers would be
\d+[^\d]+
To select the number and the last non-number, add parens:
(\d+)[^\d]*([^\d])
Finally add a /g to repeat the procedure for each match, and replace it with the 2 matched groups for each match:
js> '90+*-+80-+/*70'.replace(/(\d+)[^\d]*([^\d])/g, '$1$2');
90+80*70
js>
Or you can use lookahead assertion and simply remove all non-numerical characters which are not last: "90+*-+80-+/*70".replace(/[^0-9]+(?=[^0-9])/g,'');
You can use a regular expression to match the non-digits and a callback function to process the match and decide what to replace:
var test = "90+*-+80-+/*70";
var out = test.replace(/[^\d]+/g, function(str) {
return(str.substr(-1));
})
alert(out);
See it work here: http://jsfiddle.net/jfriend00/Tncya/
This works by using a regular expression to match sequences of non-digits and then replacing that sequence of non-digits with the last character in the matched sequence.
i would use this tutorial, first, then review this for javascript-specific regex questions.
This should do it -
var string = "90+*-+80-+/*70"
var result = '';
var arr = string.split(/(\d+)/)
for (i = 0; i < arr.length; i++) {
if (!isNaN(arr[i])) result = result + arr[i];
else result = result + arr[i].slice(arr[i].length - 1, arr[i].length);
}
alert(result);
Working demo - http://jsfiddle.net/ipr101/SA2pR/
Similar to #Arnout Engelen
var string = "90+*-+80-+/*70";
string = string.replace(/(\d+)[^\d]*([^\d])(?=\d+)/g, '$1$2');
This was my first thinking of how the RegEx should perform, it also looks ahead to make sure the non-digit pattern is followed by another digit, which is what the question asked for (between two numbers)
Similar to #jfriend00
var string = "90+*-+80-+/*70";
string = string.replace( /(\d+?)([^\d]+?)(?=\d+)/g
, function(){
return arguments[1] + arguments[2].substr(-1);
});
Instead of only matching on non-digits, it matches on non-digits between two numbers, which is what the question asked
Why would this be any better?
If your equation was embedded in a paragraph or string of text. Like:
This is a test where I want to clean up something like 90+*-+80-+/*70 and don't want to scrap the whole paragraph.
Result (Expected) :
This is a test where I want to clean up something like 90+80*70 and don't want to scrap the whole paragraph.
Why would this not be any better?
There is more pattern matching, which makes it theoretically slower (negligible)
It would fail if your paragraph had embedded numbers. Like:
This is a paragraph where Sally bought 4 eggs from the supermarket, but only 3 of them made it back in one piece.
Result (Unexpected):
This is a paragraph where Sally bought 4 3 of them made it back in one piece.

Categories

Resources