0

I'm trying to build validation for an address field in a file

The file is like so;

123 Strata Ln.
15 138th Ave
27 Hilltop Dr. Apt. 7
F52 Milk Ln.
156A Fantastic St.
56 sample Ln.

These are the conditions:

Number​ - at least one digit, followed by an arbitrary number of additional digits

Street Name​ - An arbitrary number of words (at least one) each beginning with a capital letter or number, followed by any number of lower and upper case letters, numbers, or periods (.)

EDIT: With these conditions, only the first three lines of the file are valid

Here's what i've tried

'^[[:digit:]][[:digit:]]+ ([[:upper:]]|[[:digit:]])([[:alphabet:]]|[[:digit:]])+\.$'

but it doesn't seem to work. Any help?

4
  • 1
    [[:alphabet:]] is not valid. You probably want [[:alpha:]], also there is [[:alnum:]] which may come in handy. And the first bit matches at least two digits, not one, due to the +, and you force a dot at the end. Please also let us know what the expected outcome is given the data you list.
    – Kusalananda
    Jun 16, 2018 at 13:12
  • Also please be more specific than "it doesn't seem to work": how did you apply it (in particular, what regex engine and what if any matching options did you use)? what did you expect to happen? what actually happened? Jun 16, 2018 at 13:17
  • Are you reading this file with bash or grep or something else?
    – Jeff Schaller
    Jun 16, 2018 at 13:27
  • @JeffSchaller I was reading the file with 'while read' and passing the file as input. Then comparing each line to the regex I had built Jun 16, 2018 at 13:29

1 Answer 1

3

at least one digit, followed by an arbitrary number of additional digits

+ is already "one or more", so [[:digit:]][[:digit:]]+ would require at least two. So [[:digit:]]+.

words (at least one) each beginning with a capital letter or number, followed by any number of lower and upper case letters, numbers, or periods (.)

A capital or a number: [[:upper:][:digit:]], no need for alternation (|) here as we can use both character classes inside the brackets at the same time.

[[:alphabet:]] isn't a valid character class, but there's alpha and alnum (for letters or numbers). The latter might be useful.

A single word: [[:upper:][:digit:]][[:alnum:].]*

Multiple words, with blanks in front of each (that takes care of the blank after the leading number too): ([[:blank:]]+[[:upper:][:digit:]][[:alnum:].]*)+

And since you want to match the full line, add ^ and $ to the ends, or use grep -x. You may want to add [[:blank:]]* to the end (before $) to allow for trailing blanks which are easy to leave by accident.

This would only print the first three lines of your sample input:

grep -E '^[[:digit:]]+([[:blank:]]+[[:upper:][:digit:]][[:alnum:].]*)+$' file

There's an online tool for playing with regexes in https://regex101.com/ which you may find useful for testing. Note that the above requires grep -E because of the + (the alternative is ugly), but I don't think regex101 allows to use plain basic grep regexes.

2
  • 1
    Or grep -x instead of the anchoring.
    – Kusalananda
    Jun 16, 2018 at 13:24
  • Thank you so much for your help and clear explanation. Very appreciated Jun 16, 2018 at 13:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.