admin管理员组

文章数量:1206399

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

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

Share Improve this question edited May 22, 2012 at 11:19 Fabrizio Calderan 123k26 gold badges170 silver badges182 bronze badges asked May 22, 2012 at 11:16 Paul Chops HelyerPaul Chops Helyer 931 silver badge5 bronze badges 2
  • what do you exactly mean with "how to use the regex as a mask" ? – Fabrizio Calderan Commented May 22, 2012 at 11:21
  • I would like to be able to convert the string to match the regex. E.G. if I have a regex to validate a string matches, I would like to be able to format a string accordingly (primarily in this case to insert a space in the relevant part of the postcode) – Paul Chops Helyer Commented May 22, 2012 at 11:53
Add a comment  | 

3 Answers 3

Reset to default 20

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.)

本文标签: javascriptReformat string containing uk postcode using regexStack Overflow