Skip to content

Commit 88ab6a7

Browse files
committed
New mask types and error with masked value
1 parent 55bb833 commit 88ab6a7

3 files changed

Lines changed: 123 additions & 59 deletions

File tree

README.md

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,38 @@ import (
2020
)
2121

2222
func main() {
23-
maskedValue, _ := strmask.Apply("LLL-000-0", "ABC1234")
24-
fmt.Println(maskedValue) // out: ABC-123-4
25-
26-
maskedValue, _ = strmask.Apply("LLL-000-0", "ABC-123-4")
27-
fmt.Println(maskedValue) // out: ABC-123-4
28-
29-
maskedValue, _ = strmask.Apply("LLL-000-0", "ABC1234XYZ")
30-
fmt.Println(maskedValue) // out: ABC-123-4
23+
// Ex. phone number
24+
maskedValue, _ := strmask.Apply("+0 (000) 000-00-00", "12345678900")
25+
fmt.Println(maskedValue) // out: +1 (234) 567-89-00
26+
27+
// Ex. phone number with err
28+
maskedValue, err := strmask.Apply("+0 (000) 000-00-00", "12345")
29+
if err != nil {
30+
fmt.Println(err) // out: invalid value
31+
}
32+
fmt.Println(maskedValue) // but maskedValue out: +1 (234) 5
33+
34+
// Ex. ID
35+
maskedValue, _ = strmask.Apply("####-####-####-####", "1234qwerasdfzxcv")
36+
fmt.Println(maskedValue) // out: 1234-qwer-asdf-zxcv
37+
38+
// Ex. Passport
39+
maskedValue, _ = strmask.Apply("00 0000000", "123456789")
40+
fmt.Println(maskedValue) // out: 12 3456789
41+
42+
// Ex. code
43+
maskedValue, _ = strmask.Apply("G-UUUUUU", "q1w2e3")
44+
fmt.Println(maskedValue) // out: G-Q1W2E3
3145
}
32-
3346
```
3447

3548

3649
## Mask Symbols
3750
Symbol | Meaning
3851
--- | ---
39-
`0` | Requires a decimal digit at this position
40-
`L` | Requires a unicode letter and digit at this position
41-
`l` | Requires a unicode letter at this position
52+
`#` | Requires a unicode letter or digit at this position
53+
`0` | Requires a digit at this position
54+
`L` | Requires a unicode letter (will be lower) or digit at this position
55+
`l` | Requires a unicode letter (will be lower) at this position
56+
`U` | Requires a unicode letter (will be upper) or digit at this position
57+
`u` | Requires a unicode letter (will be upper) at this position

strmask.go

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,58 +6,80 @@ import (
66
)
77

88
const (
9-
Letter = 'l'
10-
LetterDigit = 'L'
9+
LetterDigit = '#'
1110
Digit = '0'
11+
12+
LowerLetterDigit = 'L'
13+
LowerLetter = 'l'
14+
15+
UpperLetterDigit = 'U'
16+
UpperLetter = 'u'
1217
)
1318

1419
var ErrValue = errors.New("invalid value")
1520

1621
func Apply(mask, value string) (string, error) {
17-
var err error
18-
runes := make([]rune, len(mask))
22+
valueRunes := []rune(value)
23+
runes := make([]rune, 0, len(mask))
1924
cursor := 0
20-
for i, mT := range mask {
21-
runes[i], err = getRune(mT, value, &cursor)
22-
if err != nil {
23-
return "", err
25+
26+
var r rune
27+
for _, mT := range mask {
28+
if isMaskType(mT) {
29+
r = getRune(mT, valueRunes, &cursor)
30+
if r == -1 {
31+
return string(runes), ErrValue
32+
}
33+
} else {
34+
r = mT
2435
}
36+
runes = append(runes, r)
2537
}
2638

27-
str := string(runes)
28-
return str, nil
39+
return string(runes), nil
2940
}
3041

31-
func getRune(maskType rune, value string, cursor *int) (rune, error) {
42+
func getRune(maskType rune, value []rune, cursor *int) rune {
3243
if (*cursor) > len(value)-1 {
33-
return 0, ErrValue
44+
return -1
3445
}
3546

36-
r := rune(value[*cursor])
37-
38-
if maskType == r {
39-
*cursor++
40-
return maskType, nil
41-
} else if isMaskType(maskType) {
42-
*cursor++
43-
if (maskType == LetterDigit && isLetterDigit(r)) ||
44-
(maskType == Letter && unicode.IsLetter(r)) ||
45-
(maskType == Digit && unicode.IsDigit(r)) {
46-
return r, nil
47-
}
48-
return getRune(maskType, value, cursor)
49-
} else {
50-
return maskType, nil
47+
r := value[*cursor]
48+
*cursor++
49+
50+
// # - Requires a unicode letter or digit at this position
51+
// 0 - Requires a digit at this position
52+
if (maskType == LetterDigit && isLetterOrDigit(r)) || (maskType == Digit && unicode.IsDigit(r)) {
53+
return r
5154
}
55+
56+
// L - Requires a unicode letter (will be lower) or digit at this position
57+
// l - Requires a unicode letter (will be lower) at this position
58+
if (maskType == LowerLetterDigit && isLetterOrDigit(r)) || (maskType == LowerLetter && unicode.IsLetter(r)) {
59+
return unicode.ToLower(r)
60+
}
61+
62+
// U - Requires a unicode letter (will be upper) or digit at this position
63+
// u - Requires a unicode letter (will be upper) at this position
64+
if (maskType == UpperLetterDigit && isLetterOrDigit(r)) || (maskType == UpperLetter && unicode.IsLetter(r)) {
65+
return unicode.ToUpper(r)
66+
}
67+
68+
return getRune(maskType, value, cursor)
5269
}
5370

54-
func isLetterDigit(r rune) bool {
71+
func isLetterOrDigit(r rune) bool {
5572
return unicode.IsLetter(r) || unicode.IsDigit(r)
5673
}
5774

5875
func isMaskType(r rune) bool {
5976
switch r {
60-
case LetterDigit, Letter, Digit:
77+
case LetterDigit,
78+
Digit,
79+
LowerLetterDigit,
80+
LowerLetter,
81+
UpperLetterDigit,
82+
UpperLetter:
6183
return true
6284
default:
6385
return false

strmask_test.go

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,43 +16,69 @@ func TestApply(t *testing.T) {
1616
wantErr bool
1717
}{
1818
{
19-
name: "success",
19+
name: "mask-# (any letter or digit)",
2020
args: args{
21-
mask: "LLL-LLL-LLL",
22-
value: "A23456ABC",
21+
mask: "####-####-####-####",
22+
value: "qwer TYUI 0123-4567",
2323
},
24-
want: "A23-456-ABC",
24+
want: "qwer-TYUI-0123-4567",
2525
},
2626
{
27-
name: "success",
27+
name: "mask-0 (only digit)",
2828
args: args{
29-
mask: "0000-000-0",
30-
value: "123456789",
29+
mask: "+0 (000) 000-00-00",
30+
value: "A12345678900",
3131
},
32-
want: "1234-567-8",
32+
want: "+1 (234) 567-89-00",
3333
},
3434
{
35-
name: "success",
35+
name: "mask-L (lower letter or digit)",
3636
args: args{
37-
mask: "0000-000-0",
38-
value: "9999-123-4",
37+
mask: "LLLL-LLLL",
38+
value: "QWER 1234",
3939
},
40-
want: "9999-123-4",
40+
want: "qwer-1234",
4141
},
4242
{
43-
name: "error",
43+
name: "mask-l (lower letter)",
4444
args: args{
45-
mask: "0000-000-0",
46-
value: "9999-123-",
45+
mask: "llll-llll",
46+
value: "QWER 1234 zxCV",
4747
},
48+
want: "qwer-zxcv",
49+
},
50+
{
51+
name: "mask-U (upper letter or digit)",
52+
args: args{
53+
mask: "UUUU-UUUU",
54+
value: "qwer 1234",
55+
},
56+
want: "QWER-1234",
57+
},
58+
{
59+
name: "mask-u (upper letter)",
60+
args: args{
61+
mask: "uuuu-uuuu",
62+
value: "qwer 1234 ASDV",
63+
},
64+
want: "QWER-ASDV",
65+
},
66+
{
67+
name: "error mask",
68+
args: args{
69+
mask: "uuuu-uuuu",
70+
value: "123345",
71+
},
72+
want: "",
4873
wantErr: true,
4974
},
5075
{
51-
name: "error",
76+
name: "error mask with value",
5277
args: args{
53-
mask: "0000-000-0",
54-
value: "asdasdasdas",
78+
mask: "uuuu-uuuu",
79+
value: "qwer",
5580
},
81+
want: "QWER-",
5682
wantErr: true,
5783
},
5884
}

0 commit comments

Comments
 (0)