题目:
Given a text file file.txt
that
contains list of phone numbers (one per line), write a one liner bash script to print all valid phone numbers.
You may assume that a valid phone number must appear in one of the following two formats: (xxx) xxx-xxxx or xxx-xxx-xxxx. (x means a digit)
You may also assume each line in the text file must not contain leading or trailing white spaces.
For example, assume that file.txt
has
the following content:
987-123-4567 123 456 7890 (123) 456-7890Your script should output the following valid phone numbers:
987-123-4567 (123) 456-7890
第一次尝试:
1
2
|
# Read from the file file.txt and output all valid phone numbers to stdout. grep '[(0-9][0-9][0-9)][- ][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]' file.txt |
1、刚开始以为是要去除重复的号码,后来仔细审题才发现,题目要求仅仅是去除格式不符合的号码。
2、也就是说只需要输出符合格式的号码即可,于是想到了用正则表达式
3、使用grep过滤命令,[]
表示或,只要满足里面任意一个字符即可,如[Ss]表示大小写的s都可以
- 表示-本身,[- ]表示满足-或者空格即可
[0-9]表示一个数字字符
结果报错:
错误原因:
忽略了如果电话号码既包含(,又有数字开头的边界条件,这个确实不好想到。。
第二次尝试:
1
|
grep '^(\{0,1\}[0-9]\{3\}\{0,1\}[-
][0-9]\{3\}-[0-9]\{4\}$' file.txt |
加入了开头标识符^,同时发现其实可以将[0-9][0-9][0-9]替换成[0-9]\{3\}
结果报错:
错误原因:
第三个数字之后,不是)和空格,就是-。这个问题我没有注意到
第三次尝试:
1
|
grep "^(\{0,1\}[0-9]\{3\}\(-\|) \)[0-9]\{3\}-[0-9]\{4\}$" file.txt |
第三个数字之后可以写成\(-\|) \)表示接下来的子串是 - 或者 ) 空格,其中 \ 是转义字符,告诉系统 () 和 | 不是匹配字符串的一部分
通过man grep可以发现如下提示:
Basic vs Extended Regular Expressions
In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead use the backslashed
versions \?, \+, \{, \|, \(, and \).
在基本正则表达式BRE中,?, +, {, |, (, )将失去其特殊意义,如果不加转义字符\,则会被认为是匹配字符串的一部分
结果报错:
发现头部又匹配出错了,看来还是分析的不够透彻。
认真研究(xxx) xxx-xxxx和xxx-xxx-xxxx发现,原来头部不是(xxx)空格就是xxx-
因此又是二选一的,那么我们直接把这两个选项加到头部即可
第四次尝试:
1
|
grep "\(^([0-9]\{3\}) \|^[0-9]\{3\}-\)[0-9]\{3\}-[0-9]\{4\}$" file.txt |
\( (xxx)空格 \| xxx- \) xxx-xxxx
结果通过:
本题知识点:
一、grep过滤
grep '匹配字符串表达式' 文件
二、基本正则表达式中特殊字符
在基本正则表达式BRE中,?, +, {, |, (, )将失去其特殊意义,如果不加转义字符\,则会被认为是匹配字符串的一部分
三、对由多个字符组成的多个匹配子串,进行或操作
需要用到 或运算符 | 和小括号 ( ),同时要注意对这些特殊字符进行转义