点号的使用

点号.匹配(几乎)任何字符


在正则表达式中,点号.是最常用的元字符之一。不幸的是,它也是最常被滥用的元字符。 

.匹配单个字符,而无需关心该字符是什么。然而点.是不能匹配换行符的。在本教程中讨论的所有regex风格中,默认情况下,.都不与换行符匹配。  

存在该例外主要是由于历史原因。使用正则表达式的第一个工具是基于行的。他们将逐行读取文件,然后将正则表达式分别应用于每一行。效果是,使用这些工具,字符串永远不会包含换行符,因此.永远无法匹配它们。

现代工具和语言可以将正则表达式应用于非常大的字符串甚至整个文件。除了JavaScript和VBScript以外,此处讨论的所有正则表达式都可以选择使.与所有字符匹配,包括换行符。   

在Perl中,.与换行符匹配的模式称为“单行模式”。这有点不幸,因为很容易将此术语与“多行模式”混淆。多行模式仅影响锚点,而单行模式仅影响.。我们可以通过在正则表达式代码后添加模式修饰符s来激活单行模式,如下所示:m/^regex$/s; 。  

其他语言和正则表达式库都采用了Perl的术语。使用.NET框架的regex类时,可以通过指定RegexOptions.Singleline来激活此模式,例如在Regex.Match(“ string”,“ regex”,RegexOptions.Singleline)中。   

JavaScript和VBScript没有使点匹配换行符的选项。在这些语言中,可以使用诸如[\s\S]之类的字符类来匹配任何字符。该字符与不是空白字符(包括换行符)或不是空白字符的字符匹配。由于所有字符都是空格或非空格,因此此字符类与任何字符匹配。       

在所有Boost的regex语法中,默认情况下,.匹配换行符。Boost的ECMAScript语法使我们可以使用regex_constants::no_mod_m将其关闭。  

换行符


尽管在正则表达式中,对.的支持是普遍的,但是在将它们视为换行符的字符方面却存在显着差异。所有样式都将\n视为换行符。UNIX文本文件使用单个换行符终止行。本教程中讨论的所有脚本语言都不会将其他任何字符视为换行符。即使在Windows中文本文件通常以\r\n换行的情况下,这也不是问题。这是因为默认情况下,这些脚本语言以文本模式读取和写入文件。在Windows上运行时,\r\n对在读取文件时会自动转换为\n ,并且\n会自动以\r\n写入文件。             

std :: regexXML SchemaXPath还将回车符\r视为换行符。JavaScript在此之上添加了Unicode行分隔符\u2028和段落分隔符\u2029 。Java包括这些字符以及Latin-1下一行控制字符\u0085 。Boost将换页\f添加到列表中。只有Delphi和JGsoft Flavor支持所有Unicode换行符,并通过垂直选项卡完成混合。                       

.NET是Windows开发框架,它不会自动从读取的文本文件中剥离回车符。如果将Windows文本文件整体读取为字符串,它将包含回车符。如果在该字符串上使用正则表达式abc.* ,而未设置RegexOptions.SingleLine,则它将匹配abc以及同一行之后的所有字符,并在该行的末尾加上回车符,但之后没有换行符。       

Java具有UNIX_LINES选项,这使得它仅将\n视为换行符。PCRE具有允许我们在\n ,\r ,\r\n或所有Unicode换行符之间进行选择的选项。         

在POSIX系统上,POSIX语言环境确定哪些字符是换行符。C语言环境仅将\n视为换行符。Unicode语言环境支持所有Unicode换行符。    

\N从不匹配换行符


Perl 5.12和PCRE 8.10引入了\N ,它匹配不是换行符的任何单个字符,就像点一样。与点不同,\N不受“单行模式”影响。(?s)\N.打开单行模式,然后匹配不是换行符的任何字符,然后匹配任何字符,而不管它是否是换行符。      

PCRE控制将哪些字符视为换行符的选项对\N的影响与对点的影响完全相同。  

PHP 5.3.4和R 2.14.0也支持\N,因为它们的正则表达式支持基于PCRE 8.10或更高版本。JGsoft V2还支持\n 。   

谨慎使用点号 .


.是一个非常强大的正则表达式元字符。它让我们变得懒惰。放一个点,当我们在有效数据上测试正则表达式时,一切都很好。问题是正则表达式在不匹配的情况下也会匹配。如果我们不熟悉正则表达式,那么其中的某些情况一开始可能并不那么明显。

让我们用一个简单的例子来说明这一点。假设我们要以mm/dd/yy格式匹配日期,但我们要让用户选择日期分隔符。快速解决方案是\d\d.\d\d.\d\d 。起初看起来不错。它匹配的日期如03/12/02就好了。问题是:该正则表达式也将02512703视为有效日期。在此匹配中,第一个点匹配5,第二个点匹配7。显然不是我们想要的。       

\d\d[-/.]\d\d[-/.]\d\d是更好的解决方案。此正则表达式允许使用破折号,空格,点和正斜杠作为日期分隔符。请记住,点不是字符类中的元字符,因此我们不需要使用反斜杠对其进行转义。

这个正则表达式还远远不够完善。它将99/99/99匹配为有效日期。[01]\d[-/.][0-3]\d[-/.]\d\d尽管仍匹配19/39/99 ,但它已经更接近我们的期望了。我们希望正则表达式的完美程度取决于我们要使用的正则表达式。如果要验证用户输入,它必须是完美的。如果我们要解析一个已知来源的数据文件,并且每次都以相同的方式生成其文件,那么我们的最后一次尝试可能足以解析数据而不会出错。我们可以在示例部分中找到更好的正则表达式来匹配日期。

使用否定的字符类代替点号 .


一个否定字符类通常比点更合适。本教程量词部分解释了重复运算符星号和加号,并且进行了详细介绍。但是警告也很重要,在这里也要提及。再次让我们举例说明。    

假设我们要匹配双引号字符串。听起来很简单。我们可以在双引号之间包含任意数量的任何字符,因此" .* "似乎可以解决问题。.匹配任何字符,星号允许点重复任意次,包括零次。如果我们在目标字符串This is a "string" between double quotes 上测试此正则表达式,则它与“string”匹配就很好了。现在继续在字符串 We have a problem with "string one" and "string two". Please respond. 上应用此正则表达式。正则表达式匹配出字符串 "string one" and "string two" 。绝对不是我们想要的。这是因为星号*很贪心。    

在日期匹配示例中,我们通过用字符类替换点来改进了正则表达式。在这里,我们对否定的字符类进行相同的处理。我们最初对双引号字符串的定义是错误的。我们不希望引号之间包含任何数量的任何字符。我们需要任意数量的字符,这些字符不是双引号或引号之间的换行符。所以,正确的正则表达式是"[^"\r\n]*"。如果你的正则表达式支持速记符\v匹配任何换行符,那么"[^"\v]*"是一个更好的解决方案。          

查看笔记

扫码一下
查看教程更方便