I'm trying to get the last String (from the right hand side) of the cells in a column but I cant figure it out.
I have this code that would get the first three digits from the left hand side but yeah that wont work.
var first_3_digs = values.filter(r => {
if(r.toString().includes('_')){return r;}
}).map(r=> r.toString().split('_')[0]);
For example if I want as an input CS_1*44u i want the output u. Same for ml, l etc...
If you need more info please let me know.
Thank you so much for the help.
Example how to get the 'units' from several cells:
const unit = x => /[\d]+[\D]+/.test(x) ? x.match(/[A-z]+$/)[0] : '';
var texts = ['CS_1*44u', 'Case', '72x64ml', '11x37kg', '123'];
texts.forEach(x => console.log(unit(x))); // --> 'u', '', 'ml', 'kg', ''
Example how to get the 'unit' from one cell:
const unit = x => /[\d]+[\D]+/.test(x) ? x.match(/[A-z]+$/)[0] : '';
var cell_value = 'CS_1*44u';
console.log(unit(cell_value)); // --> 'u'
If you need to get the array of the 'units' from another array of cells you can map the function this way:
const unit = x => /[\d]+[\D]+/.test(x) ? x.match(/[A-z]+$/)[0] : '';
var cells = ['CS_1*44u', 'Case', '72x64ml', '11x37kg', '123'];
var units = cells.map(x => unit(x)); // <---- here
console.log(units); // --> ['u', '', 'ml', 'kg', '']
as you have tagged formulas for possible solution, i will offer the following REGEXEXTRACT formula:
=REGEXEXTRACT(K1,"[^(\d+(\.\d+)?)(?!.*\d+(\.\d+)?)]*$")
explanation:
AFTER last occurrence of "a":
[^a]*$
LAST digit (with or without decimal):
(\d+(\.\d+)?)(?!.*\d+(\.\d+)?)
[EDIT]
where \d means a number, here is a (shorter) alternative which is also tested as working with the same dataset:
=REGEXEXTRACT(K1,"[^\d]*$")
Related
I have a scenario like Need to edit the single quotes values (only single quotes values),
So I extracted the single quotes values using regex and prepare the reactive dynamic form.
onclick of performing edit button will show old step name above, new step name below, submit step will replace the step name in the original array.
WOrking fine as expected in few scenarios according to my approach, but in scenarios, I realized whatever algorithm I am following does not fulfill my requirement.
Below are the test cases
Test case 1:
Step Name: "Then I should hire an employee using profile '1' for 'USA'",
// Here --> '1', 'USA' values are editable
Test case 2: "And Employee should be hired on '01' day of pay period '01' of 'Current' Fiscal"
// '01', '01', 'Current'
Issues: in test case 2 if I tried to edit second 01 it is editing the first 01
I try to solve the perform edit function with help of indexof, substring functions
this.replaceString = this.selectedStep.name;
this.metaArray.forEach((element: any) => {
var metaIndex = this.replaceString.indexOf(element.paramValue);
if (metaIndex !== -1) {
const replaceValue = this.stepEditForm.controls[element['paramIndex']].value;
this.replaceString = this.replaceString.substring(0, metaIndex) + replaceValue + this.replaceString.substring(metaIndex + (element.paramValue.length));
}
});
but in indexof always find the first occurrence of a value in a string. So I realized my approach is wrong on performed it function
please find the attachment for the code
https://stackblitz.com/edit/angular-reactive-forms-cqb9hy?file=app%2Fapp.component.ts
So Can anyone please suggest to me how to solve this issue,
Thanks in advance
I added a function called matchStartingPositions that returns the starting position indexes of each match. Using this method you can then perform your edit by replacing the string just as you do, but we'll find the proper match to be replaced at the given position.
So in your line
var metaIndex = this.replaceString.indexOf(element.paramValue);
we can then add a second parameter to indexOf, that is the starting point:
var metaIndex = this.replaceString.indexOf(element.paramValue, startingPositions[element.paramIndex]);
The function for getting the index positions just looks for those single quotes in a given string:
matchStartingPositions(str) {
let count = 0;
let indices = [];
[...str].forEach((val, i) => {
if (val === "'") {
if (count % 2 == 0) {
indices.push(i);
}
count++;
}
});
return indices;
}
Here it is in action:
https://angular-reactive-forms-xhkhmx.stackblitz.io
https://stackblitz.com/edit/angular-reactive-forms-xhkhmx?file=app/app.component.ts
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 have used the below code to split my string.
splitter.map((item1) => {
let splitter1 = item1.split("=")[0].trimLeft();
let splitter2 = item1.split("=")[1].trimRight();
});
where item1 contains string as
Labor_Agreement=0349BP
Default_Hours=5/8
Probation_Period=>=12 Months
The issue I am facing is to restrict the amount of splits. Because the above code will fail in case of third string , i.e. Probation_Period=>=12 Months
I tried giving parameter to restrict the amount of split in split method above, but that is giving syntax error.
An easy to understand solution would consist of first finding the first = character, and slicing you array twice to get the right portion :
const strings = [
'Labor_Agreement=0349BP',
'Default_Hours=5/8',
'Probation_Period=>=12 Months',
];
strings.map(item => {
const chSplit = item.indexOf('=');
const splitter1 = item.slice(0, chSplit).trim();
const splitter2 = item.slice(chSplit + 1).trim();
console.log(splitter1, splitter2);
});
I need to develop an javascript function to check the mask reversely.
It means,
if I set the mask "###:##",
When I type "1" it shows, "1" When I
type "2" it shows, "21"
When I type "3"
it shows ,"3:21"
etc..
Is it possible to develop like that??
I have no idea how to start it? Can anyone put me on the right direction?
Update:
What the OP wants is a way to pass a custom mask to an input and have it auto-mask on every keypress - my original answer was assuming a hardset mask.
This is not a final solution, but should get you started if you don't want to use a plugin:
Jsfiddle (does not do what OP requests exactly at the moment) - but gets close.
var masker = {
mask : '', // custom mask that will be defined by user
types : {
'#' : '[\\d]', // number
'z': '[\\w]', // alpha
'*': '[\\d\\w]' // number or alpha
},
maskMatch : '', // regex used for matching
maskReplace : '', // replace string
makeTemplate : function(){
// basically we want to take the custom mask
// and make it into a regex match with capture groups
// and a replace string with the added separator(s)
// first we need to split the mask into like groups:
// ex: ###:## -> [#,#,#][:][#,#]
// so we get the indexes to slice it up later
var m = masker.mask.split('');
var len = m.length-1;
var indexes=[];
for (var i=0;i<len;i++){
if(m[i]!=m[i+1]){
indexes.push(i);
}
}
// now we slice it into groups
var groups = [];
for(var i=0;i<=indexes.length;i++){
var start = (i==0) ? 0 : indexes[i-1]+1;
var end = (i==indexes.length) ? m.length : indexes[i]+1;
groups.push(m.slice(start,end));
}
console.log(groups);
var reg = '';
var groupCount=1; // replace starts with $1
var replace = '';
// loop through to see if its using a wildcard
// replace with the wildcard and the number to match
// this will need to be reworked since it assumes
// {1,n} -- can't change the 1 at this moment
for(var i=0;i<groups.length;i++){
var l = groups[i][0];
if(l!='#'&&l!='z'&&l!='*'){
replace+= groups[i].join('');
continue;
}
replace+='$'+groupCount;
groupCount++;
reg+='(';
reg+=masker.types[l];
if(groups[i].length>1){
reg+='{1,';
reg+= groups[i].length;
reg+='}';
}
reg+=')';
}
console.log(reg);
console.log(replace);
masker.maskReplace = replace;
masker.maskMatch = new RegExp(reg);
},
matchIt: function(text)
{
// only replace if is match
if(text.match(masker.maskMatch)){
text = text.replace(masker.maskMatch,masker.maskReplace);
}
return text;
},
setup: function(id){
// you need a way to store the actual numbers (non-masked version)
// this is quick way, but should be incorporated as a variable
var hiddenText = $(id).clone().css({'left':'-9999px','position':'absolute'}).prop('id',id.substring(1,id.length)+'hidden').appendTo($(id));
$('#maskme').bind('keyup',function(e){
// fix this to better handle numpad, etc
var c = String.fromCharCode(e.which);
if(c.match(/[\w\d]/)){
$(id+'hidden').val( $(id+'hidden').val()+c);
$(id).val(masker.matchIt($(id+'hidden').val()));
} else {
// need a way to tell if user has highlighted then backspace
// or highlight and space... basically something for highlighting
if(e.which==8){ // 8 is backspace
// update our hidden value / stored value with what the user wants
var old = $(id+'hidden').val();
$(id+'hidden').val( old.substring(0,old.length-1));
}
}
});
}
}
Then calling it:
masker.mask = '###:##';
masker.makeTemplate();
masker.setup('#maskme');
If you want something more advanced take a look at the jQuery Masked Input project over a github. It already has handlers for all the different keypresses and other events, a more flexible custom matching, and many other things that should be thought about.
I have a table like this I'd like to sort :
| Name | Case |
| John | X-123/08 P|
| Bob | X-123/09 |
| Dylan | X-45/10 |
I want to sort the Case colum by case's year then case's number knowing that the format is always "X-(1 to 4 digits for case's number)/(case's year on 2 digits) (sometimes some text)". It's possible that after the year's case I have some text but it shoud be ignored for sorting.
I am using tablesorter jQuery's plugin and I am struggling to add a custom parser for this.
Thanks for your help !
EDIT : Here's what I'm trying to do :
jQuery.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
return false;
},
format: function(s) {
// format your data for normalization
return s.replace(/^X-\d{1,4}\/(\d{2}).*$/, '$1') + ('000' + s.replace(/^X-(\d{1,4})\/\d{2}.*$/, '$1')).substr(-4);
},
// set type, either numeric or text
type: 'text'
});
It's working great until I encounter a case with 2 digits which is then ranked greater than a 3 digits one and I don't understand why ...
"X-458/09 P" is sorted smaller than "X-48/09" . I'll try some debug to see what really happens.
EDIT 2 : Also tried the second answer :
jQuery.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
return false;
},
format: function(s) {
var m = s.match(/X\-(\d+)\/(\d{2}).*$/);
var affaire = m[1];
var year = m[2];
return year + '000' + affaire;
},
// set type, either numeric or text
type: 'text'
});
The result seems to be the same as the first one... I really can't understand why it sucks. Why tablesorter thinks that 488 000 10 is smaller than 49 000 10 ?!
I think you can use:
$.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
// return false so this parser is not auto detected
return false;
},
format: function(s) {
// format your data for normalization
return s.replace(/^X-\d{1,4}\/(\d{2}).*$/, '$1') + ('000' + s.replace(/^X-(\d{1,4})\/\d{2}.*$/, '$1')).slice(-4);
},
// set type, either numeric or text
type: 'text'
});
EDIT:
Maybe you already tried something like this with type: 'numeric'; I'm not sure, but this may fail because parseInt('09') === 0.
EDIT 2:
Changed to reflect sorting by year, then case number.
You can use a regex to get the 2 values you're after, for example:
var columnVal = "X-123/08";
var m = columnVal.match(/X\-(\d+)\/(\d{2})$/);
var case = m[1];
var year = m[2];
After trying multiple things this one seems to work perfectly well :
jQuery.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
return false;
},
format: function(s) {
var m = s.match(/X\-(\d+)\/(\d{2}).*$/);
var caseVar = '000' + m[1];
var size = caseVar.length;
caseVar= caseVar.substr(size-4, 4);
var year = m[2];
return jQuery.tablesorter.formatFloat(year + caseVar);
},
// set type, either numeric or text
type: 'numeric'
});
I did some research and it appears that the substr function with a negative value doesn't work on all browser (I'm using IE because my application must be IE compliant). I think that's the cause of my previous problems and that's why Spiny's solution wasn't working for me.
Thanks anyway to all of you for your precious help !