2.1.3 Intertwined RegularExpressions
我们继续改进此程序:能够接收浮点数;容许f或者c是小写;容许数字和字母之间存在空格。
a. 增加处理浮点数的正则:
/^([-+]?[0-9]+(\.[0-9]*)?)([CF])$/
新的引用捕获文本的变量,如下图:
b. 增加数字和字母之间存在空格的正则:
/^([-+]?[0-9]+(\.[0-9]*)?) *([CF])$/
上面划线部分,我们无法分清是空格还是TAB!为了解决这个问题,我们使用「\s」。
现在的表达式:
/^([-+]?[0-9]+(\.[0-9]*)?)\s*([CF])$/
c. 增加不区分大小写字母:
为了解决这个问题,需要增加i这个“修饰符(modifier)”,即把它放在「/…/」结构之后。
/^([-+]?[0-9]+(\.[0-9]*)?)\s*([CF])$/i
完整代码:
#! /usr/bin/perl -w
# Mastering Regular Expressiona: Chapter 2 Section 2.
# second program
print "Enter a temperature (e.g., 32F, 100C):\n";
$input = <STDIN>;
chomp($input);
if ($input =~ /^([-+]?[0-9]+(\.[0-9]*)?)\s*([CF])$/i) {
$inputNum = $1;
$type = $3;
#if (($type eq "C") | ($type eq "c")) {
if ($type =~ /c/i) {
$celsius = $inputNum;
$fahrenheit = ($celsius * 9 / 5) + 32;
}
else {
$fahrenheit = $inputNum;
$celsius = ($fahrenheit - 32) * 5 / 9;
}
printf "%.2f C is %.2f F\n", $celsius, $fahrenheit;
}
else {
print "Expecting a number followed by \"C\" or \"F\",\n";
print "so I don't understand \"$input\".\n";
}
2.1.4 Intermission
²Perl 用$variable =~ m/regex/ 来判断一个正则是否能匹配某个字符串。M表示“匹配(match)”,而斜线用来标注正则的边界(它们本身不属于正则表达式)。整个测试语句作为一个单元,返回true或者false值。
²元字符—具有特殊意义的字符。他的定义在正则表达式中并不是统一的。元字符的含义取决于具体的情况。了解具体情况(shell、正则表达式、字符串),其中的元字符及其作用,对学习和使用Perl、PHP、Java、Tcl、GNU Emacs、awk、Python或其他高级语言是非常重要的(当然,在正则表达式内部,字符组(character classes)有自己的“子语言”,其中的元字符是不同的)。
²Perl和其他流派的正则表达式提供了许多有用的简记法(shorthands):
\t 制表符
\n 换行符
\r 回车符
\s 任何“空白”字符(例如空格符、制表符、进纸符等)
\S 除「\s」之外的任何字符
\w 「[a-zA-Z0-9]」(在「\w+」中很有用,可以用来匹配一个单词)
\W 除「\w」之外的任何字符,也就是「[^a-zA-Z0-9]」
\d 「[0-9]」,即数字
\D 除「\d」外的任何字符,即「[^0-9]」
²/i修饰符(modifier)表示此测试不区分大小写。尽管写法是“/i”,其实“i”只是跟在表示结尾的斜线之后。
²「(?:…)」这个麻烦的写法可以用来分组文本,但并不捕获。
²匹配成功之后,Perl可以用$1、$2、$3之类的变量来保存相对应的「(…)」小括号内的子表达式匹配的文本。使用这些变量,我们能够用正则表达式从字符串中提取信息。
子表达式的编号按照开括号“(”的出现先后排序,从1开始。子表达式可以嵌套,例如「(Washington(·DC)?)」。如果只是希望分组,也可以使用「(…)」,但副作用是,它们捕获的文本仍然会保存到特殊的变量(例如,$1, $2, $3 etc.,)中。