When developing, we often come across code we’ve seen hundreds of times that we just copy and paste from project to project. Sometimes it’s so banal that it’s not worth trying to improve, change or even modularize it. Ctrl-C + Ctrl-V may be the cheapest and fastest solution, ergo, the best.
This is the kind of situation we see when masks must be applied to text fields
such as Social Security Numbers (SSN), Telephones, Zip Codes, and so on. Those
awful few dozens of lines we copy from one textField:shouldChangeCharactersInRange:replacementString:
to the other. It never changes because it works. There’s no need to improve it.
It’s always the same. But I’ve got tired of it. That nasty code that, in a well
structured class, can be as a mole in a beautiful woman’s face.
A few days ago I got some spare time and I started working on something I though could come handy. So how do you simplify and generalise this problem that every developer has to face at least once? Easy! Regex! Wait.. You sure it’s easy? I’ll tell you, it wasn’t easy, but we’re talking about patterns in varying occasions and, as I visualised it, regex is the best, simplest and most “approachable” solution. I mean, everybody knows a little bit of regex.
While modelling, I wanted to make it as simple and as clean as possible, therefore, for now, there are only two classes, and only one method you’ll really use, but you can read the complete documentation. From now on, I’ll present a superficial approach to introduce this small library.
Fork the Github Repo!
NSStringMask
The NSStringMask is the main class responsible for applying your masks to the
NSStrings. Among it’s methods the only noteworthy is
[NSStringMask maskString:withPattern:placeholder:]
.
It formats the given string
based on the pattern
you provide, filling the
voids with the placeholder
. It automatically creates an instance of
NSRegularExpression with the option CaseInsensitive
, so if you need a different
option, you may use the alternate method which expects a regex instead of pattern
.
There’s also an alternative method that receives no placeholder
(same as nil
),
in this case, when the given string
is shorter than expected, instead of
applying the mask, the method will return a cleaned string having only the
valid characters based on validCharactersForString:
.
Important Note
Doesn’t matter if providing a pattern
or an instance of regex, the regular
expression must have capturing groups (parentheses). This is because the
class understands that everything that is not within parentheses is part of the
mask and must be interpreted as literal characters!
Suppose you’re formatting a SSN, whose regex pattern is \d{3}-\d{2}-\d{3}
.
If you provide that regex/pattern, nothing will be formatted because the class
will think that \d{3}
is part of the mask, and not 3 numbers that should go there.
The correct usage is: (\d{3})-(\d{2})-(\d{3})
Obs: If Xcode is showing a warning about unknown escape sequences, try
adding double slashes (\\d
)
UITextFieldMask
This is a subclass of UITextField, so you can set your nibs to use this class and automatically apply masks to your text fields.
Obviously, you must provide a mask to transform your strings, and it’s
recommended that you do so when initialising your view or view controller.
So you should set the text field’s mask inside viewDidLoad
or awakeFromNib
.
Suppose you have a view with an outlet to an UITextFieldMask named textFieldMask
:
A question for you: what does that mask accepts?
Installation
You can install it from Cocoa Pods,
or clone the project from the Github Repo
and copy the files in the folder Classes
.
Helpful stuff
I’ve also created this gist with some common patterns. Feel free to improve it!