了解你的正则表达式

正则表达式 (regexps)的概念(一种描述与一组字符串匹配的模式的符号)在许多程序和语言中都很常见。 这些各种正则表达式实现的细节在某种程度上有所不同,但是学习构建正则表达式的原理对所有人都是通用的。

本文介绍了一些有用的工具和技术,这些工具和技术可用于学习在各种UNIX®应用程序中构建和完善正则表达式,包括:

突出显示上下文中的匹配项

生成正则表达式时,有助于查看模式在数据集的上下文中匹配的字符串。 考虑清单1的四行输入文本和与两个字符模式匹配的平凡regexp t[az]

清单1.四行示例文本以及一个与之匹配的正则表达式
$ cat midsummer
I know a bank where the wild thyme blows,
Where oxlips and the nodding violet grows,
Quite over-canopied with luscious woodbine,
With sweet musk-roses and with eglantine. 
$ grep t[a-z] midsummer
I know a bank where the wild thyme blows,
Where oxlips and the nodding violet grows,
Quite over-canopied with luscious woodbine,
With sweet musk-roses and with eglantine. 
$

因为它在每一行上都找到至少一个与其两个字符模式匹配的字符,所以grep命令输出输入文件中的每一行。 但是正则表达式匹配那些输入行上的哪些字符?

借助像这样的琐碎正则表达式,您可以很容易地自信地盯着它。 但是,当您构建复杂的正则表达式并拥有大型数据集或输入文件时,要知道正则表达式可能匹配的字符串会变得非常困难。 能够准确查看每行匹配的文本很有用。 在上下文中查看正则表达式的一种方法是在输出中标记它们。

您可以使用几个应用程序来做到这一点,包括grepsed和Emacs。

用grep突出显示

当使用--color选项时,某些较新版本的grep (例如GNU grep )会用颜色突出显示正则表达式, 如图1所示。

图1.在grep中着色的匹配字符串
匹配的字符串在grep中着色

如果您的终端支持颜色,这是一种精确查看正则表达式匹配的字符串的有用方法。

用sed突出显示

您还可以在流编辑器sed进行正则表达式突出显示。 sed命令:

's/regexp/[&]/g'

输出输入的副本,括号中包含所有regexp实例。 清单2显示了带有示例文本的输出。

清单2.用sed标记的匹配字符串
$ sed 's/t[a-z]/[&]/g' midsummer
I know a bank where [th]e wild [th]yme blows,
Where oxlips and [th]e nodding violet grows,
Qui[te] over-canopied wi[th] luscious woodbine,
Wi[th] sweet musk-roses and wi[th] eglan[ti]ne. 
$

您也可以用其他方式标记正则表达式。 如果您输入的是Groff文档,则可以在正则表达式中添加粗体,然后将文档发送给groff进行处理:

$ sed 's/t[a-z]/\\fB&\\fP/g' infile.roff | groff -

您还可以编写一个简短的sed程序,以输出颜色匹配项。 如果您的外壳支持转义序列,则可以突出显示文件上下文中的所有正则表达式。 因为转义序列的输入很麻烦,所以您无疑要从脚本运行它,如清单3所示。

清单3. sed脚本以彩色突出显示匹配的图案
#!/bin/sh
# highlights regexp pattern in input file
# usage: hre regexp file
sed 's/'$1'/^[[34m&^[[37m/g' < $2

在清单中两次出现的^[是一个文字转义字符,因此您必须使用支持输入文字字符的编辑器(例如Emacs(在其中键入Cq ESC来输入))来输入此清单。 3437是分别指定蓝色和白色的Bash转义代码。

要使脚本可执行,请键入:

$ chmod 744 hre

然后运行它, 如图2所示。

图2.用sed着色的匹配字符串
sed中匹配的字符串

虽然可以使用此方法指定突出显示颜色和纯色,但也有一些注意事项。 例如, 清单3中所示的脚本仅在终端的纯文本为白色时才有效,因为它将文本还原为该颜色。 如果您的终端使用不同的颜色显示纯文本,请在脚本中更改转义码。 (例如, 30是黑色。)

用Emacs突出显示

在新版本的GNU Emacs编辑器中, isearch-forward-regexpisearch-backward-regexp函数会突出显示缓冲区中的所有匹配项。 如果您在系统上安装了最新版本的Emacs,请立即尝试:

  1. 通过键入以下命令来启动Emacs:
    $ emacs midsummer
  2. 键入Mx isearch-forward-regexp

    Mx是Meta-x组合的Emacs表示法,您可以通过按住Alt键, X并释放两个键,或者通过按Esc键将其释放,然后按X来在大多数系统上键入键。

  3. 输入正则表达式以搜索: t[az]

    由于搜索是渐进式的,因此 Emacs在键入单个字符时便开始突出显示匹配项-在这种情况下,当您按T键时,缓冲区中的所有T字符都将突出显示。 请注意,一旦您开始输入方括号中的字符列表,突出显示就会消失,并且Emacs会在迷你缓冲区中报告它没有足够的输入来显示匹配项。

    您的Emacs会话应如图3所示

    图3.一个Emacs缓冲区,在上下文中显示了一个regexp
    一个Emacs缓冲区,在上下文中显示一个正则表达式
  4. 键入Cx Cc退出Emacs。

    您可以通过按住Ctrl键,按X ,然后按住Ctrl键并按C来键入此组合。

isearch-forward-regexpisearch-backward-regexp函数通常绑定到MSsMSr击键。 (要创建它们,请按住Alt键, Ctrl键以及SR键。)

仅显示匹配项,不显示行

还有另一种解决模式上下文问题的方法,那就是只输出匹配本身,而不输出匹配发生的整个行。 有多种方法可以使用grepsedperl

仅显示具有grep的匹配项

--only-matching选项(也为-o )更改grep的行为,以便它不输出包含与regexp匹配的所有行,而仅输出匹配的行 。 如同--color选项如上所述 ,该功能显示在一些较新版本grep实现,包括GNU grep ,这是开源和可用于许多操作系统。

此选项用于收集与正则表达式匹配的数据-非常适用于收集IP地址,URL,名称,电子邮件地址,单词等,但它也是学习正则表达式的好方法。 例如, 清单4显示了如何使用它来收集清单1的示例文本中的所有单词。 它将每个单词输出到一行。

清单4.从样本文件中收集所有单词
$ egrep -o '[A-Za-z]+' midsummer
I
know
a
bank
where
the
wild
thyme
blows
Where
oxlips
and
the
nodding
violet
grows
Quite
over
canopied
with
luscious
woodbine
With
sweet
musk
roses
and
with
eglantine
$

实际上,当您为某项作业构建特别复杂的正则表达式时,使用此选项是一种简单的测试方法,以确保已正确构建它。 您经常可以立即看到您的正则表达式是否需要修复。

假设您要输出包含字符串th的测试文件中的所有单词,并且已经构建了清单5中所示的regexp来做到这一点。

清单5.输出所有带有“ th”的单词,取一个
$ egrep -o 'th[a-z]*' midsummer
the
thyme
the
th
th
th
$

哦,那不行。 您可以立即看到输出中的某些匹配项根本不是单词。 最好再试一次: 清单6考虑了th之前可能出现的单词中的所有字母。

清单6.输出所有带有“ th”的单词,取两个
$ egrep -o '[a-z]*th[a-z]*' midsummer
the
thyme
the
with
ith
with
$

好多了,但还差一点。 您会看到一个“ ith”表示该正则表达式与大写字母不匹配。 通过拉出-i选项来纠正此问题,如清单7所示。

清单7.输出所有带有“ th”的单词,取三个
$ egrep -o -i '[a-z]*th[a-z]*' midsummer
the
thyme
the
with
With
with

而已!

使用-o和一些测试数据对构建正则表达式很有帮助,因为您可能已经假设正则表达式在包含“ th”行的情况下是匹配的。 但是您不知道该表达实际上有点差。

只显示sed的比赛

您可以使用以下命令在sed执行类似的操作:

s/.*\(regexp\).*/\1/p

匹配sed表达式。 该命令仅从输入中输出匹配的模式,而不输出包含匹配项的输入行。 但是,它仅输出给定行上的最后一个实例,如清单8所示。

清单8.仅输出具有sed的匹配字符
$ sed -n 's/.*\(th[a-z]\).*/\1/p' midsummer
thy
the
$ grep -o th[a-z] midsummer
the
thy
the
$

仅显示与Perl的比赛

正则表达式在Perl语言中也很常用,但是Perl正则表达式与您使用grep构建的正则表达式不同。 pcretest工具可让您测试Perl正则pcretest 。 您可以使用此工具熟悉与Perl兼容的正则表达式(PCRE)库,并调试或测试使用它构建的正则表达式。

regexp像往常一样用斜杠(/)括起来,并且可以跟在后面的修饰符用来改变搜索的行为。 表1中提供了常见的正则表达式修饰符。

表1. pcretest的常规regexp修饰符
修饰符 描述
8 此修饰符支持Unicode(UTF-8)字符集。
g 此修饰符搜索全局匹配项(一行中有多个)。
i 该修饰符忽略大小写的差异。
m 此修饰符可搜索多行。
x 该修饰符使用扩展的Perl正则表达式。

尝试pcretest交互方式运行pcretest ,如清单9所示。

清单9.使用pcretest测试一个正则表达式
$ pcretest
PCRE version 6.7 04-Jul-2006

  re> /[a-z]*th[a-z]*/ig
data> With sweet musk-roses and with eglantine.
 0: With
 0: with
data> 
$

您也可以使用输入文件运行pcretest 。 输入文件包含要在一行上进行测试的regexp,然后是要测试的任意数量的数据行。 您可以使用空行将多个正则表达式及其各自的数据分开; pcretest继续读取正则pcretest并搜索以下几行数据,直到到达文件末尾(EOF)。

如果提供第二个文件的名称,则pcretest会将输出写入该文件。 否则,它将写入标准输出,如清单10所示。

清单10.从输入文件运行pcretest
$ cat midsummer.pre
/w[hi]|th/gi
I know a bank where the wild thyme blows,
Where oxlips and the nodding violet grows,
Quite over-canopied with luscious woodbine,
With sweet musk-roses and with eglantine. 
$ pcretest midsummer.pre
PCRE version 6.7 04-Jul-2006

/w[hi]|th/gi
I know a bank where the wild thyme blows,
 0: wh
 0: th
 0: wi
 0: th
Where oxlips and the nodding violet grows,
 0: Wh
 0: th
Quite over-canopied with luscious woodbine,
 0: wi
 0: th
With sweet musk-roses and with eglantine. 
 0: Wi
 0: th
 0: wi
 0: th
$

调出向导

txt2regex脚本是为Bash shell构建的交互式,跨平台正则表达式“向导”。 当您运行它时,它会向您询问有关您要匹配的模式的一系列问题,然后它会为任意数量的两个十几种不同的应用程序构建有效的正则表达式:

  • awk
  • ed
  • egrep
  • emacs
  • expect
  • find
  • gawk
  • grep
  • javascript
  • lex
  • lisp
  • mawk
  • mysql
  • ooo
  • perl
  • php
  • postgres
  • procmail
  • python
  • sed
  • tcl
  • vbscript
  • vi
  • vim

除了帮助您以交互方式构建正则表达式外,txt2regex还提供了针对各种语言和应用程序的正则表达式语法的简要摘要,与常用模式匹配的“就绪正则表达式”列表以及一个方便的正则表达式元字符图表。

建立一个正则表达式

要为txt2regex 支持的一个或多个应用程序构建一个regexp,请在逗号分隔的列表中提供这些应用程序的名称,作为--prog选项的参数。

首先尝试构建在上下文部分的“ 突出显示”匹配中给出的平凡正则表达式,该正则表达式匹配T字符,后跟小写字母:

  1. 启动txt2regex并为grepsed和Emacs指定正则表达式:
    $ txt2regex --prog grep,sed,emacs
  2. 您要在行的任何部分而不是仅在行的开头匹配T字符,因此请键入2以选择“在行的任何部分”。
  3. 再次键入2以选择“特定字符”,然后在询问匹配哪个字符时键入t

    现在,您必须回答要匹配多少次。

  4. 输入1以指定一次。
  5. 通过键入6以选择“特殊组合”来匹配任何小写字母,然后键入b以匹配小写字母。 输入. 退出组合子菜单。
  6. 通过键入1将小写字母完全匹配一次。

在执行该过程时,txt2regex会为三个选定的应用程序中的每个构建regexp,并将其显示在屏幕顶部附近。 现在,您已经完全选择了想要的内容,可以在图4中看到所有三个应用程序所需的正则表达式。

图4.使用txt2regex构建一个regexp
使用txt2regex构建正则表达式

键入..退出。 正则表达式列表将保留在您的终端上。

是的,所有三个正则表达式碰巧都写为相同的t[az] ,但这仅是因为这是一个简单的正则表达式,并且所选的三个应用程序都具有类似的正则表达式语法。 对于所有选择的应用程序,构建的正则表达式不一定总是一样。

举例来说,假设您要构造在仅显示匹配项而不是行部分中使用的两个正则表达式。 第一个是一个大写或小写字母的单词:

  1. 不带任何选项启动txt2regex:
    $ txt2regex
  2. 键入2以匹配该行的任何部分。
  3. 键入6以给出特殊的组合,然后键入ab以选择所有大写和小写字母。
  4. 输入. 返回主菜单,然后键入4以指定应匹配一次或多次。

如果没有选项,则txt2regex默认为perlphppostgrespythonsedvim应用程序构建正则表达式。 完成上述操作后,您会发现前四个应用程序使用与清单4中的 grep相同的正则表达式,但是sedvim正则表达式略有不同。 这是因为这些应用程序使用的元字符表示法略有不同, 如下所述

再次输入..退出程序。 各种应用程序的正则表达式将保留在您的终端上。 您可以按显示使用它们,也可以对其进行编辑以进一步完善它们。 例如,匹配包含撇号(')字符的单词怎么办? 不,是谁,是所有者的,“原因,乔的等等”? 您刚刚构建的regexp将无法正确匹配它们,如您所见, 仅显示匹配项 (请参见清单11 )。

清单11.带有撇号的单词不正确匹配
$ echo "Don't miss a word, just 'cause it's wrong." | egrep [A-Za-z]+
Don
t
miss
a
word
just
cause
it
s
wrong
$

您需要将连字符添加到该括号列表中,并再次进行演示,如清单12所示。 请注意,您必须立即引用正则表达式。

清单12.正确匹配带有撇号的单词
$ echo "Don't miss a word, just 'cause it's wrong." | egrep "[A-Za-z']+"
Don't
miss
a
word
just
'cause
it's
wrong
$

在“ 仅显示匹配项而不是行”部分中使用的下一个正则表达式是针对单词中包含“ th”的单个单词。 您已经为egrepsedperl使用了正则表达式; 现在尝试为普通grep构建它:

  1. 启动txt2regex:
    $ txt2regex
  2. 键入/选择程序,然后键入hkopqstx. 这样就只会为grep建立一个正则表达式。
  3. 键入26ab.3以选择行上任何位置的零个或多个大写或小写字母。
  4. 键入2t12h1 ,在2t12h1跟字符T和H,每个字符恰好出现一次。
  5. 键入6ab.3以跟随零个或多个大写或小写字母。
  6. 键入..退出程序。

您可以测试刚刚构建的regexp,如清单13所示。

清单13.将包含“ th”的单词与grep匹配
$ grep -o [A-Za-z]*th[A-Za-z]* midsummer
the
thyme
the
with
With
with
$

获取正则表达式选项的摘要

--showinfo选项仅输出有关为特定程序或语言构建正则--showinfo的信息的简短摘要。 输出中包括应用程序的名称和版本,正则表达式元字符,默认转义元字符,默认情况下需要转义的元字符,是否可以在方括号列表中使用制表符以及其是否支持可移植操作系统接口(POSIX)括号。表达式。

如果您是从事多个应用程序的开发人员,那么这是快速获取特定应用程序的regexp规则的好方法,如清单14所示。

清单14.使用txt2regex获取正则表达式规则的摘要
$ txt2regex --showinfo javascript

   program  javascript: netscape-4.77
     metas  . [] [^] * + ? {} | ()
  esc meta  \
  need esc  \.*[{(|+?^$
  \t in []  YES
 [:POSIX:]  NO

$ txt2regex --showinfo php

   program  php: 4.0.6
     metas  . [] [^] * + ? {} | ()
  esc meta  \
  need esc  \.*[{(|+?^$
  \t in []  YES
 [:POSIX:]  YES

$

准备好正则表达式

作者将--make选项描述为“头痛的补救方法”。 它为作为参数给出的几种常见模式之一输出一个正则表达式,如表2所示

表2. txt2regex中可用的现成正则表达式列表
论据 描述
date 此参数匹配mm/dd/yyyy格式的日期,范围从00/00/0000到99/99/9999。
date2 此参数匹配mm/dd/yyyy格式的日期,从00/00/1000到19/39/2999。
date3 此参数匹配mm/dd/yyyy格式的日期,从00/00/1000到12/31/2999。
hour 该参数匹配hh:mm格式的时间,从00:00到99:99。
hour2 此参数以hh:mm格式匹配时间,从00:00到29:59。
hour3 此参数以hh:mm格式匹配时间,从00:00到23:59。
number 此参数匹配任何正整数或负整数。
number2 此参数将任何具有可选浮点值的正整数或负整数匹配。
number3 此参数将任何具有可选逗号和可选浮点值的正整数或负整数匹配。

例如,您可以使用它来获取在军事时间内任何有效小时的正则表达式,如清单15所示。

清单15.使用txt2regex获取日期regexp
$ txt2regex --make hour3

 RegEx perl    : ([01][0-9]|2[0123]):[012345][0-9]
 RegEx php     : ([01][0-9]|2[0123]):[012345][0-9]
 RegEx postgres: ([01][0-9]|2[0123]):[012345][0-9]
 RegEx python  : ([01][0-9]|2[0123]):[012345][0-9]
 RegEx sed     : \([01][0-9]\|2[0123]\):[012345][0-9]
 RegEx vim     : \([01][0-9]\|2[0123]\):[012345][0-9]

$

了解你的元字符

另一个有用的txt2regex选项是--showmeta ,它输出一个表,该表包含用于为支持的应用程序构建正则--showmeta的所有元字符。 清单16中显示了此选项。

清单16.显示所有带有txt2regex的元字符
$ txt2regex --showmeta

       awk       +       ?               |      ()
        ed      \+      \?    \{\}      \|    \(\)
     egrep       +       ?      {}       |      ()
     emacs       +       ?              \|    \(\)
    expect       +       ?               |      ()
      find       +       ?              \|    \(\)
      gawk       +       ?      {}       |      ()
      grep      \+      \?    \{\}      \|    \(\)
javascript       +       ?      {}       |      ()
       lex       +       ?      {}       |      ()
      lisp       +       ?             \\|  \\(\\)
      mawk       +       ?               |      ()
     mysql       +       ?      {}       |      ()
       ooo       +       ?      {}       |      ()
      perl       +       ?      {}       |      ()
       php       +       ?      {}       |      ()
  postgres       +       ?      {}       |      ()
  procmail       +       ?               |      ()
    python       +       ?      {}       |      ()
       sed      \+      \?    \{\}      \|    \(\)
       tcl       +       ?               |      ()
  vbscript       +       ?      {}       |      ()
        vi   \{1\}  \{01\}    \{\}            \(\)
       vim      \+      \=     \{}      \|    \(\)

NOTE: . [] [^] and * are the same on all programs.

$

研究文档

阅读手册是值得的。 您的系统可能比您可能意识到的更多有关构建和使用正则表达式的文档,包括手册页。

例如, grepsed和其他类似工具的手册页描述了它们的regexp语法并提供了示例。 如果您的系统上安装了GNU版本,则他们的Info文档中可能还包含比通常的手册页更多的信息-有时会在其中安装整个用户手册。 例如,如果您已安装GNU sed并具有info二进制文件,则可以阅读手册:

$ info sed

Perl文档(通常与主要Perl源代码或二进制软件包分开打包和分发)包含有关Perl正则表达式的完整手册页:

$ man perlre

这个主题还有更多。 pcrepattern手册页( 如上所述 ,随pcretest应用程序一起分发)还描述了Perl正则表达式。

最后,可在许多UNIX系统上使用的regex手册页提供了有关构建POSIX regexp的信息。 此手册页上的信息来自Henry Spencer的regex库(请参阅参考资料 )。

摘要

UNIX系统上有许多用于正则表达式构建的工具和方法。 您刚刚学到了其中一些最好的方法。

这些工具提供了强大的方法来设计,测试和改进正则表达式。 在UNIX系统上使用这些工具和技术可能是学习构建复杂的正则表达式的最佳方法。 而且也很有趣!


翻译自: https://www.ibm.com/developerworks/aix/library/au-regexp/index.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值