Reformat string containing uk postcode using regex - javascript

How can I format a string using Javascript to match a regex?
I am using UK postcodes which could match any of the following
N1 3LD
EC1A 3AD
GU34 8RR
I have the following regex which validates a string correctly, but I am unsure how to use the regex as a mask to format EC1A3AD to EC1A 3AD / GU348RR to GU34 8RR / N13LD to N1 3LD.
My regex is /^[A-Za-z]{1,2}[0-9A-Za-z]{1,2}[ ]?[0-9]{0,1}[A-Za-z]{2}$/
Thank you

If you use the regular expression /^([A-Z]{1,2}\d{1,2}[A-Z]?)\s*(\d[A-Z]{2})$/ you can extract the two parts of the postcode and reassemble them with an intervening space.
var list = ['N13LD', 'EC1A3AD', 'GU348RR'];
for (var i = 0; i < list.length; i++) {
var parts = list[i].match(/^([A-Z]{1,2}\d{1,2}[A-Z]?)\s*(\d[A-Z]{2})$/);
parts.shift();
alert(parts.join(' '));
}
output
N1 3LD
EC1A 3AD
GU34 8RR

Put braces around the bits separated by the optional space:
/^([A-Za-z]{1,2}[0-9A-Za-z]{1,2})[ ]?([0-9]{0,1}[A-Za-z]{2})$/
However I think the regexp is wrong... The above regexp splits "N13LD" as "N13", "LD".
I suspect the errant part is the {0,1} before the two trailing letters - there must AFAIK be exactly one digit there:
var re = /^([A-Z]{1,2}[\dA-Z]{1,2})[ ]?(\d[A-Z]{2})$/i; // case insensitive
The grouping allows the string.match(regexp) function to return a result which includes an entry for each matching group:
> "N13LD".match(re);
["N13LD", "N1", "3LD"]
> "GU348RR".match(re);
["GU348RR", "GU34", "8RR"]
> "EC1A3AD".match(re);
["EC1A3AD", "EC1A", "3AD"]
To get your result, just use trivial string concatenation to join the 2nd and 3rd element from each result together.

I've used the excellent answer from #borodin above to create a UK postcode as-you-type formatter. Note, this does not validate the postcode, just formats it according to borodin's regex as the user types.
var txtPc = $("#postcode");
var outputCount = 0;
var jigCount = 0;
var postcodePauseTime = 500;
txtPc.on("keydown", function(e) {
var keyCode = e.which;
var key = String.fromCharCode(keyCode);
var isAlphaNumeric = //key.match(/^[a-z0-9]+$/i);
(
(keyCode >= 65 && keyCode <= 90) ||
(keyCode >= 48 && keyCode <= 57) ||
([189, 190, 8, 46, 9].indexOf(keyCode) > -1) ||
(keyCode >= 35 && keyCode <= 40)
);
return !!isAlphaNumeric;
});
// handle click and add class
txtPc.on("keyup", function(e) {
PostcodeCalculateFormat(txtPc);
});
txtPc.on("blur", function() {
PostcodeCalculateFormat(txtPc);
});
function PostcodeCalculateFormat(txtPc) {
(function(index, txtPc) {
setTimeout(function() {
//prevent interferance from other keypresses by returning out of this closure
if (index != jigCount) return;
var isFocused = ($('#' + txtPc.attr('id') + ':focus')[0] == document.activeElement);
var postcodeText = txtPc.val().toUpperCase(); /// + key;
var origSpacePos = postcodeText.indexOf(" ");
postcodeText = postcodeText.replace(/[\W_]+/g, "");
var parts = postcodeText.match(/^([A-Z]{1,2}\d{1,2}[A-Z]?)\s*(\d[A-Z]{2})$/i);
//if unable to match the lot, try the first part only with less strict reg
if (!parts)
parts = postcodeText.match(/^([A-Z]{1,2}\d{1,2}[A-Z]?)\s*(.*)$/i);
if (parts) {
var caretPos = 0;
if (isFocused)
caretPos = getCaretPosition(txtPc[0]).start;
parts.shift();
var newVal = parts.join(' ');
if (newVal == txtPc.val())
return;
output(newVal);
txtPc.val(newVal);
var spacePos = newVal.indexOf(" ");
if (isFocused) {
if (caretPos >= spacePos && origSpacePos == -1)
caretPos++;
setCaretPosition(txtPc[0], caretPos, caretPos);
}
}
}, postcodePauseTime);
}(++jigCount, txtPc));
}
function output(str) {
$("#listOutput").prepend("<li>[" + (++outputCount) + "] " + str + "</li>");
}
function getCaretPosition(ctrl) {
// IE < 9 Support
if (document.selection) {
ctrl.focus();
var range = document.selection.createRange();
var rangelen = range.text.length;
range.moveStart('character', -ctrl.value.length);
var start = range.text.length - rangelen;
return {
'start': start,
'end': start + rangelen
};
}
// IE >=9 and other browsers
else if (ctrl.selectionStart || ctrl.selectionStart == '0') {
return {
'start': ctrl.selectionStart,
'end': ctrl.selectionEnd
};
} else {
return {
'start': 0,
'end': 0
};
}
}
function setCaretPosition(ctrl, start, end) {
// IE >= 9 and other browsers
if (ctrl.setSelectionRange) {
ctrl.focus();
ctrl.setSelectionRange(start, end);
}
// IE < 9
else if (ctrl.createTextRange) {
var range = ctrl.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
}
body {
background: silver;
padding: 20px;
font-family: Helvetica;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div>Sample postcodes to type: 'BT92PE', 'EC1A3AD', 'GU348RR', 'N13LD'</div>
<div>
Postcode: <input id="postcode" style="text-transform: uppercase; " />
</div>
<!-- for troubleshooting -->
<ul id="listOutput"></ul>
The caret get & set functions were taken straight from a stack overflow answer, which I can't find right now to give the user credit. I will look & update with a link if I can.
This does everything I want it to, but it's not a very elegant solution. I'm happy for somebody out there to revamp, enhance or improve on this. I'd like to see the result.
Improvement for future: if the caret is after the space, the backspace key should remove the space AND the alphanumeric character before it in one key press. (same idea for the delete button if the caret is in before the space.)

Related

Vue.js KeyUpEventHandler: Caret position after formatting the entered numbers with comma - thousand delimiter

I would like to format entered numbers with comma - thousand delimiter like that (1000000 -> 1000,000). For this purpose I want to use KeyUpEventHandler: #keyup.stop=“KeyUpEventHandler”. The issue is that - I cannot move the position of Caret at the end of a text.
I found that it’s possible to do with Javascript Range but I never used it before. Could you help me to fix my code please. Thanks!
KeyUpEventHandler: function(event) {
var self = this;
var evt = event || window.event;
var charCode = event.which || event.keyCode;
// skip for arrow keys:
if(charCode >= 37 && charCode <= 40) return;
var value = event.target.innerHTML;
var len = value.length;
console.log("value: " + value +" len: " + len);
var commaFormatted = value.replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",");
if (typeof window.getSelection != "undefined") {
var el = window.getSelection();
console.log(el);
if (el.getRangeAt && el.rangeCount) {
var range = el.getRangeAt(0);
var lastChild = el.lastChild; //null
//var endOffset = el.childNodes.length;
//el.innerHTML = commaFormatted; //not visible for Vue
var spanEl = self.$refs[self.refName];
spanEl.innerHTML = commaFormatted;
//var range = spanEl.getRangeAt(0);
//range.setEnd(spanEl, len);
range.setEndAfter(lastChild); //.setEndAfter**strong text**(spanEl, endOffset);
}
}
},
Sorry please for misunderstanding. There is no issue with formatting numbers:
formatNumber: function(num) {
var parts = num.split('.');
var part1 = parts[0];
var part2 = parts.length > 1 ? '.' + parts[1].substring(0, 2) : ''; // always two decimal digits
//BAD: https://blog.abelotech.com/posts/number-currency-formatting-javascript/ <-- BAD
//BAD: return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); //BAD
return part1.replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",") + part2;
},
The issue is only with Cursor (Caret) Position at elements that are editable by the user:
css -webkit-user-modify: read-write;
Thank you all! I found a working solution:
formatNumber: function(num) {
var parts = num.split('.');
var part1 = parts[0];
var part2 = parts.length > 1 ? '.' + parts[1].substring(0, 2) : ''; // always two decimal digits
return part1.replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",") + part2;
},
KeyUpEventHandler: function(event) {
var self = this;
var evt = event || window.event;
var charCode = evt.which || evt.keyCode;
// skip for arrow keys - we want to allow navigation around textbox using arrow keys
if(charCode >= 37 && charCode <= 40) return;
if (typeof window.getSelection != "undefined") {
var selection = window.getSelection();
var value = event.target.innerHTML;
var len = value.length;
var commaFormatted = self.formatNumber(value);
var el = self.$refs[self.refName];
el.innerHTML = commaFormatted;
if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
{
range = document.createRange();
range.selectNodeContents(el);
range.collapse(false); //collapse the range to the end point. false means collapse to end rather than the start
selection.removeAllRanges();//remove any selections already made
selection.addRange(range);
} else if(document.selection)//IE 8 and lower
{
range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
range.select();//Select the range (make it the visible selection
}
};
}

jquery add dash between characters if length is greater than x

I am trying to format a US zip code as the user types, and need to add a dash between the 5th and and 6th characters if the user types more than 5 so the the zip code is formatted like
55555 or 55555-5555
what I have now adds a dash, but regardless if a 6th number is added
//zip code formatting
$(".zip-val").keyup(function() {
if($(this).val().length == 5) {
$(this).val($(this).val() + "-");
}
});
How about this?
//zip code formatting
$(".zip-val").keyup(function() {
zipcode = $(this).val();
zipcode = zipcode.replace(/-/g, ''); // remove all occurrences of '-'
if(zipcode.length > 5) {
$(this).val(zipcode.substring(0, 5) + "-" + zipcode.substring(5));
}
});
Could try this, splitting it and keeping the number groups then recreating the string with formats. This even deletes the - if you are not in a group of 5.
You could also modify this to fit into a credit card number system.
//zip code formatting
$(".zip-val").keyup(function() {
let val = $(this).val();
if(val.length > 5) {
let digits = val.split(/(\d{1,5})/);
let str = "";
for (let group of digits)
{
if (/^\d+$/.test(group))
{
str += group + "-";
}
}
str = str.substring(0, str.length - 1);
$(this).val(str);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="zip-val" />
you should check if the length is 6 or not. Also, you can add more check, if the users use backspace on the 6th character, it would also delete the '-' character
$(".zip-val").keyup(function(e) {
if(e.keyCode == 8)
{
if($(this).val().length == 6){
var newText = $(this).val().substring(0 , 5);
$(this).val(newText);
}
}
else if($(this).val().length == 6) {
var newText = $(this).val().substring(0 , 5) + '-' + $(this).val().substring(5);
$(this).val(newText);
}
});
demo : https://jsfiddle.net/sn5ghvb8/
You can try this.
$(".zip-val").keyup(function() {
if($(this).val().length > 5 ) {
res = $(this).val().split("");//convert string to array
if(jQuery.inArray( "-", res )){//checks if dash exist
for (var i=res.length-1; i>=0; i--) {//removes dashes
if (res[i] === '-') {
res.splice(i, 1);
}
}
res.splice(5, 0, "-");
}
$(this).val(res.join(''));
}
});

Using regex to restrict input in textbox [duplicate]

This question already has answers here:
HTML input that takes only numbers and the + symbol
(7 answers)
Closed 5 years ago.
/^+{0,1}(?:\d\s?){11,13}$/ this regex allows + at first place only and numbers only...
on keypress I want user should only be able to type + at first and digits that what above regex validates But code always goes to if part..why regex not working in this scenario
function ValidatePhone(phone) {
var expr = /^\+?(?:\d\s?){11,13}$/;
return expr.test(phone);
}
var countofPlus = 0;
$("#phone").on("keypress", function (evt) {
if (evt.key == "+")
{
countofPlus = countofPlus + 1;
if (countofPlus > 1 || this.value.length >= 1) {
return false;
}
else return true;
}
var charCode = (evt.which) ? evt.which : event.keyCode
if (charCode > 31 && charCode != 43 && charCode != 32 && charCode != 40 && charCode != 41 && (charCode < 48 || charCode > 57))
return false;
return true;
});
$("#phone").on("keyup", function (evt) {
debugger;
if (evt.key == "+") {
countofPlus--;
return true;
}
});
Adapting an answer from HTML input that takes only numbers and the + symbol to your use-case yields the following (IE-)compatible code:
// Apply filter to all inputs with data-filter:
var inputs = document.querySelectorAll('input[data-filter]');
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
var state = {
value: input.value,
start: input.selectionStart,
end: input.selectionEnd,
pattern: RegExp('^' + input.dataset.filter + '$')
};
input.addEventListener('input', function(event) {
if (state.pattern.test(input.value)) {
state.value = input.value;
} else {
input.value = state.value;
input.setSelectionRange(state.start, state.end);
}
});
input.addEventListener('keydown', function(event) {
state.start = input.selectionStart;
state.end = input.selectionEnd;
});
}
<input id='tel' type='tel' data-filter='\+?\d{0,13}' placeholder='phone number'>
Above code takes copy & pasting, selecting, backspacing etc. into account where your current implementation fails.
Also, I modified the given regex to \+?\d{0,13} so it allows for incomplete input. Use HTML5 form validation to validate the final result.
I think this regex is being applied only to the char code i.e. a string of length 1. In this case regex will always fail.
Instead, try running the regex test on the input value.

Javascript: Validation for special characters

I'm working on some validations and can't seem to wrap my head around checking for special chars, none should be used. Currently I grab the value, make an array and check for uppercase and numbers. I need a way to check for special chars as well. Another small issue I found is that it passes an uppercase when a number is entered. Just looking for some direction on how to tackle this.
$('.tooltip').on({
focusin: function(){ //make
var top = $(this).offset().top
var left = $(this).offset().left + $(this).outerWidth()
$('.tip').remove()
$('body').append("<div class='tip' style='top:"+ top +"px;left:"+left+"px;'><div class='arrow'></div></div>")
$('.tip').animate({width: 'show', opacity: 'show'})
$(tipContent).appendTo('.tip')
},
focusout: function(){ //remove
$('.tip').fadeOut(function(){$(this).remove()})
},
keyup: function(){ if (event.keyCode == 16) return //validate
var val = $(this).val()
validate(val.split(""), val);
},
})
function validate(letters, val){
for (var i = 0; i < letters.length; i++){
if( letters[i] === letters[i].toUpperCase() ) { //uppercase check
console.log(letters[i] + ": " + 'Uppercase Passed');
}else{console.log('Uppercase Failed');
}
if( letters.length >= 9 ) { //min limit
console.log(letters[i] + ": " + 'Minimum Limit Passed');
}else{console.log('Minimum Limit Failed');
}
if( parseInt(letters[i]) > 0 ) { //number check
console.log(parseInt(letters[i]) + ' passed');
}else{console.log('at least 1 char failed');
}
}
}
An option might be to use regular expressions, which make your requirements easy to formulate:
function validate(value) {
var regex = /^[A-Z0-9]*$/; // consist only of uppercase letters and digits
var digit = /\d/; // contains a digit
if (regex.test(value) && digit.test(value) && value.length >= 9)
console.log("Test passed");
else
console.log("Test failed");
}
You even could combine them to one regex:
function validate(value) {
return /^(?=.*\d)[A-Z0-9]{9,}$/.test(value);
// | | | |
// string / | consists \ string end
// beginning | of only
// / upper alphabet letters and numbers,
// somewhere ahead at least 9 of them
// comes a digit
}
OK, if you need these steps separately, we should be able to do that. To recognice uppercase letters we just could use the regex [A-Z], but then umlauts etc wouldn't be recognized. If you handled them as special chars, we can easily use this regex:
/^(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]).{9,}$/
| | |
digit uppercase special char
If you don't want that (or the same regexes applied as single-steps), we can test for special characters with the following condition: It is not upper- or lower-caseable, and it is not a digit.
function validation(value) {
var uc = false,
lc = false,
sc = false,
di = false,
len = value.length;
for (var i=0; i<len; i++) {
var letter = value.charAt(i),
isUpper = letter.toUppercase() == letter,
isLower = letter.toLowercase() == letter;
if (isUpper && !isLower)
uc = true;
else if (isLower && !isUpper)
uc = true;
else // isLower && isUpper - no alphabetic character
if (/\d/.test(letter))
di = true;
else
sc = true;
}
return {
someUppercase: uc,
someLowercase: lc,
someSpecial: sc,
someDigit: di,
length: len,
longEnough: len >= 9
};
}

Removing unwanted characters from textbox with JQuery

What I would like to get some input on is how to remove certain characters from a textbox (or textarea) with JQuery. I have the code in C# but I can´t seem to translate that to JQuery javascript. My problem is that I don´t know how to get the value from a textbox as a character array which I then can loop through and compare against a given set of unwanted characters.
This is how "far" I have come in JQuery:
$("input[type=text], textarea").change(function() {
// code here
});
This is my code in C#:
for (int i = 0; i < charArray.Length; i++)
{
current = charArray[i];
if ((current == 0x9) ||
(current == 0xA) ||
(current == 0xD) ||
((current >= 0x20) && (current <= 0xD7FF)) ||
((current >= 0xE000) && (current <= 0xFFFD)))
_validXML.Append(current);
}
return _validXML.ToString().TrimEnd((char)32, (char)160) ;
UPDATE:
I went with a combination of some answers below (I will upvote them) and my final JQuery looks like this and works:
$(document).ready(function() {
$(":text, textarea").change(function() {
var text = "";
var arr = $(this).val()
$.each(arr, function(i) {
var c = arr.charCodeAt(i);
if ((c == 0x9) ||
(c == 0xA) ||
(c == 0xD) ||
(c >= 0x20 && c <= 0xD7FF) ||
(c >= 0xE000 && c <= 0xFFFD))
{
text += arr.charAt(i);
}
});
$(this).val(text);
});
});
Thanks all!
Would't this be the case for regular expressions, like:
$("input[#type='text'], textarea").change(function() {
this.value = this.value.replace(/[^\w\d]+/gim,"");
});
Textarea:
<textarea id="item" name="item" rows="5" cols="80">Some text in here</textarea>
jQuery code:
var text = $('#item').val();
var newtext = "";
for (var i = 0; i < text.length; i++) {
var c = text.charCodeAt(i);
if ((c == 0x9) || (c == 0xA) || (c == 0xD) ||
(c >= 0x20 && c <= 0xD7FF) ||
(c >= 0xE000 && c <= 0xFFFD)) {
newtext += text[i];
}
}
$('#item').val(newtext);
This has actually very little to do with jQuery, methinks, except to access the text data and set it again.
You can use the charCodeAt() method combined with the length property of strings to loop through the characters in the string.
Something like:
$("input[type=text], textarea").change(function() {
var text = $(this).val()
for(var i = 0; i < text.length; ++i) {
var currentChar = text.charCodeAt(i);
// Do something with it...
});
My initial version used charAt(), but since it looks like you're dealing with Unicode code points, charCodeAt() is more appropriate.
Use an event observer (onkeydown / onkeypress / onkeyup) on the input/textarea, get the key pressed, if the key is an unwanted character, stop the event from happening.
$("input[type=text], textarea").observe('keypress', function(e) {
var keynum;
if(window.event)
{
keynum = e.keyCode
}
else if(e.which)
{
keynum = e.which
}
if(keynum == '13' || keynum == 'something else' || [...])
{
Event.stop(e);
}
});
to get the value of textarea try:
$('input[type=textarea]').change(function(){
var value = $(this).val();
...........
});
to remove unwanted character try this example .. i copy from the jquery documentation (jQuery.grep())
var arr = [ 1, 9, 3, 8, 6, 1, 5, 9, 4, 7, 3, 8, 6, 9, 1 ];
$("div").text(arr.join(", "));
arr = jQuery.grep(arr, function(n, i){
return (n != 5 && i > 4);
});
$("p").text(arr.join(", "));
arr = jQuery.grep(arr, function (a) { return a != 9; });
$("span").text(arr.join(", "));
I prefer to stop the character from getting entered in the first place, using this type of javascript function (from my shady past):
each input control has something like this on it:
onkeypress='checkKey(this,"a-zA-Z0-9","N","10");'
the function looks like:
//****************************************************************************
// Function: checkKey()
// Author: Ron Savage
// Date: 10-11-2004
//
// Description: This function tests reg exp syntax.
//****************************************************************************
function checkKey(textControl, reExpr, allCaps, maxlen)
{
popupMessage.hide();
keyStr = String.fromCharCode(event.keyCode);
textLength = textControl.value.length;
if (allCaps == 'Y')
{
keyStr = keyStr.toUpperCase();
event.keyCode = keyStr.charCodeAt(0);
}
if ( reExpr != '' )
{
reString = '[^' + reExpr + ']';
re = new RegExp(reString, 'g');
//alert('RE: ' + reString);
result = keyStr.match(re);
if (result)
{
beep();
event.returnValue = false;
showPopupMessage(textControl, result.toString() + ' not allowed!');
}
}
if ( textLength > maxlen )
{
beep();
event.returnValue = false;
showPopupMessage(textControl, 'Max length [' + maxlen + '] exceeded!');
}
//alert('Key: ' + keyStr + ' code: ' + event.keyCode);
}

Categories

Resources