Skip to content

Commit 419544f

Browse files
authored
Support for ISO 9362:2022 BIC (SWIFT) codes (#1478)
## Fixes Or Enhances #1471 **Make sure that you've checked the boxes below before you submit PR:** - [x] Tests exist or have been written that cover this particular change. @go-playground/validator-maintainers
1 parent fe37a2f commit 419544f

File tree

5 files changed

+104
-12
lines changed

5 files changed

+104
-12
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ validate := validator.New(validator.WithRequiredStructEnabled())
164164
| base64 | Base64 String |
165165
| base64url | Base64URL String |
166166
| base64rawurl | Base64RawURL String |
167-
| bic | Business Identifier Code (ISO 9362) |
167+
| bic_iso_9362_2014 | Business Identifier Code (ISO 9362:2014) |
168+
| bic | Business Identifier Code (ISO 9362:2022) |
168169
| bcp47_language_tag | Language tag (BCP 47) |
169170
| btc_addr | Bitcoin Address |
170171
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |

baked_in.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,8 @@ var (
237237
"bcp47_language_tag": isBCP47LanguageTag,
238238
"postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2,
239239
"postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field,
240-
"bic": isIsoBicFormat,
240+
"bic_iso_9362_2014": isIsoBic2014Format,
241+
"bic": isIsoBic2022Format,
241242
"semver": isSemverFormat,
242243
"dns_rfc1035_label": isDnsRFC1035LabelFormat,
243244
"credit_card": isCreditCard,
@@ -2943,11 +2944,18 @@ func isBCP47LanguageTag(fl FieldLevel) bool {
29432944
panic(fmt.Sprintf("Bad field type %s", field.Type()))
29442945
}
29452946

2946-
// isIsoBicFormat is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362
2947-
func isIsoBicFormat(fl FieldLevel) bool {
2947+
// isIsoBic2014Format is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362 2014
2948+
func isIsoBic2014Format(fl FieldLevel) bool {
29482949
bicString := fl.Field().String()
29492950

2950-
return bicRegex().MatchString(bicString)
2951+
return bic2014Regex().MatchString(bicString)
2952+
}
2953+
2954+
// isIsoBic2022Format is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362 2022
2955+
func isIsoBic2022Format(fl FieldLevel) bool {
2956+
bicString := fl.Field().String()
2957+
2958+
return bic2022Regex().MatchString(bicString)
29512959
}
29522960

29532961
// isSemverFormat is the validation function for validating if the current field's value is a valid semver version, defined in Semantic Versioning 2.0.0

doc.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,13 +1378,20 @@ More information on https://pkg.go.dev/golang.org/x/text/language
13781378
13791379
Usage: bcp47_language_tag
13801380
1381-
BIC (SWIFT code)
1381+
BIC (SWIFT code - 2022 standard)
13821382
1383-
This validates that a string value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362.
1384-
More information on https://www.iso.org/standard/60390.html
1383+
This validates that a string value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362:2022.
1384+
More information on https://www.iso.org/standard/84108.html
13851385
13861386
Usage: bic
13871387
1388+
BIC (SWIFT code - 2014 standard)
1389+
1390+
This validates that a string value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362:2014.
1391+
More information on https://www.iso.org/standard/60390.html
1392+
1393+
Usage: bic_iso_9362_2014
1394+
13881395
# RFC 1035 label
13891396
13901397
This validates that a string value is a valid dns RFC 1035 label, defined in RFC 1035.

regexes.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ const (
6868
hTMLRegexString = `<[/]?([a-zA-Z]+).*?>`
6969
jWTRegexString = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$"
7070
splitParamsRegexString = `'[^']*'|\S+`
71-
bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
71+
bic2014RegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
72+
bic2022RegexString = `^[A-Z0-9]{4}[A-Z]{2}[A-Z0-9]{2}(?:[A-Z0-9]{3})?$`
7273
semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/
7374
dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9])?$"
7475
cveRegexString = `^CVE-(1999|2\d{3})-(0[^0]\d{2}|0\d[^0]\d{1}|0\d{2}[^0]|[1-9]{1}\d{3,})$` // CVE Format Id https://cve.mitre.org/cve/identifiers/syntaxchange.html
@@ -153,7 +154,8 @@ var (
153154
hTMLRegex = lazyRegexCompile(hTMLRegexString)
154155
jWTRegex = lazyRegexCompile(jWTRegexString)
155156
splitParamsRegex = lazyRegexCompile(splitParamsRegexString)
156-
bicRegex = lazyRegexCompile(bicRegexString)
157+
bic2014Regex = lazyRegexCompile(bic2014RegexString)
158+
bic2022Regex = lazyRegexCompile(bic2022RegexString)
157159
semverRegex = lazyRegexCompile(semverRegexString)
158160
dnsRegexRFC1035Label = lazyRegexCompile(dnsRegexStringRFC1035Label)
159161
cveRegex = lazyRegexCompile(cveRegexString)

validator_test.go

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13202,7 +13202,47 @@ func TestBCP47LanguageTagValidation(t *testing.T) {
1320213202
}, "Bad field type int")
1320313203
}
1320413204

13205-
func TestBicIsoFormatValidation(t *testing.T) {
13205+
func TestBicIso2014FormatValidation(t *testing.T) {
13206+
tests := []struct {
13207+
value string `validate:"bic_iso_9362_2014"`
13208+
tag string
13209+
expected bool
13210+
}{
13211+
{"SBICKEN1345", "bic_iso_9362_2014", true},
13212+
{"SBICKEN1", "bic_iso_9362_2014", true},
13213+
{"SBICKENY", "bic_iso_9362_2014", true},
13214+
{"SBICKEN1YYP", "bic_iso_9362_2014", true},
13215+
{"SBIC23NXXX", "bic_iso_9362_2014", false},
13216+
{"S23CKENXXXX", "bic_iso_9362_2014", false},
13217+
{"SBICKENXX", "bic_iso_9362_2014", false},
13218+
{"SBICKENXX9", "bic_iso_9362_2014", false},
13219+
{"SBICKEN13458", "bic_iso_9362_2014", false},
13220+
{"SBICKEN", "bic_iso_9362_2014", false},
13221+
}
13222+
13223+
validate := New()
13224+
13225+
for i, test := range tests {
13226+
errs := validate.Var(test.value, test.tag)
13227+
13228+
if test.expected {
13229+
if !IsEqual(errs, nil) {
13230+
t.Fatalf("Index: %d bic_iso_9362_2014 failed Error: %s", i, errs)
13231+
}
13232+
} else {
13233+
if IsEqual(errs, nil) {
13234+
t.Fatalf("Index: %d bic_iso_9362_2014 failed Error: %s", i, errs)
13235+
} else {
13236+
val := getError(errs, "", "")
13237+
if val.Tag() != "bic_iso_9362_2014" {
13238+
t.Fatalf("Index: %d bic_iso_9362_2014 failed Error: %s", i, errs)
13239+
}
13240+
}
13241+
}
13242+
}
13243+
}
13244+
13245+
func TestBicIso2022FormatValidation(t *testing.T) {
1320613246
tests := []struct {
1320713247
value string `validate:"bic"`
1320813248
tag string
@@ -13212,12 +13252,46 @@ func TestBicIsoFormatValidation(t *testing.T) {
1321213252
{"SBICKEN1", "bic", true},
1321313253
{"SBICKENY", "bic", true},
1321413254
{"SBICKEN1YYP", "bic", true},
13255+
{"E097AEXX", "bic", true}, // valid under https://www.iso.org/standard/84108.html
1321513256
{"SBIC23NXXX", "bic", false},
13216-
{"S23CKENXXXX", "bic", false},
13257+
{"S23CKENXXXX", "bic", true},
1321713258
{"SBICKENXX", "bic", false},
1321813259
{"SBICKENXX9", "bic", false},
1321913260
{"SBICKEN13458", "bic", false},
1322013261
{"SBICKEN", "bic", false},
13262+
{"DEUTDEFF", "bic", true}, // 8-char classic (Germany)
13263+
{"DEUTDEFF500", "bic", true}, // 11-char with numeric branch
13264+
{"A1B2US33", "bic", true}, // digits allowed in 4!c (bank code)
13265+
{"1234US33", "bic", true}, // all digits in 4!c (2022)
13266+
{"ZZZ1USAA", "bic", true}, // mixed alnum bank + alnum location
13267+
{"AB12AE00", "bic", true}, // UAE 8-char
13268+
{"AB12AE009Z9", "bic", true}, // UAE 11-char with mixed branch
13269+
{"WG11US335AB", "bic", true}, // example-style with digits in branch
13270+
{"BNPAFRPP", "bic", true}, // France (BNP Paribas style)
13271+
{"BOFAUS3NXXX", "bic", true}, // US with default XXX branch
13272+
{"HSBCHKHHXXX", "bic", true}, // Hong Kong, default branch
13273+
{"NEDSZAJJ", "bic", true}, // South Africa 8-char
13274+
{"BARCGB22", "bic", true}, // GB 8-char
13275+
{"BARCGB22XXX", "bic", true}, // GB 11-char with XXX branch
13276+
{"0000GB00", "bic", true}, // 4!c all digits + 2!c all digits (allowed)
13277+
{"A1B2GB00XXX", "bic", true}, // valid 11-char with numeric location and XXX
13278+
{"TATRAEBX", "bic", true}, // UAE 8-char
13279+
{"TATRSABX", "bic", true}, // Saudi 8-char
13280+
{"TATREGBX", "bic", true}, // Egypt 8-char
13281+
{"TATRBHBX", "bic", true}, // Bahrain 8-char
13282+
13283+
{"DEUTDEFFF", "bic", false}, // 9-char (invalid length)
13284+
{"DEUTDEFF5", "bic", false}, // 9-char (invalid length)
13285+
{"DEUTDE", "bic", false}, // 6-char (invalid length)
13286+
{"DEUTDEFF50", "bic", false}, // 10-char (invalid length)
13287+
{"DEUTDEFF5000", "bic", false}, // 12-char (invalid length)
13288+
{"deUTDEFF", "bic", false}, // lowercase not allowed
13289+
{"DEUTDEfF", "bic", false}, // lowercase in location
13290+
{"DEU@DEFF", "bic", false}, // special char in bank
13291+
{"ABCD12FF", "bic", false}, // digits in 2!a country (invalid)
13292+
{"ABCDDE1-", "bic", false}, // hyphen in location
13293+
{"ABCDDE1_", "bic", false}, // underscore in location
13294+
{"ABCDDE١٢", "bic", false}, // non-ASCII digits in location
1322113295
}
1322213296

1322313297
validate := New()

0 commit comments

Comments
 (0)