RegEx packages/zh CN

From Lazarus wiki
Jump to navigationJump to search

Deutsch (de) English (en) español (es) Bahasa Indonesia (id) polski (pl) 中文(中国大陆) (zh_CN)
Free Pascal 包含 RegExpr 包,该包包含多个用于正则表达式的“引擎”。其中主要的引擎是 TRegExpr,其他引擎已被弃用且不再开发。

阅读关于正则表达式的 Wikipedia 页面以了解该主题:POSIX 基本正则表达式

Sorokin 的 TRegExpr

这是最完整的实现,在 FPC 的 "packages/regexpr/src/regexpr.pas" 文件中可用。此包实现了 Perl 正则表达式的一个子集,并且该包提供的语法在 这里有文档说明

官方仓库:GitHub。开发在那里进行,FPC 包会稍晚一些跟随这个仓库。来自该仓库的版本在 FPC 中运行良好。

2019/2020 年的改进

在 2019 年之前,大约 15 年没有任何人提交补丁之后,Alexey TorgashinUser:Alextp 继续了 TRegExpr 的工作。这些更改已合并到 FPC Git 的“main”分支中。

更改包括:

  • 优化。一个主要的优化使得测试基准项目(在官方 GitHub 仓库中)在 1-2 个测试中速度提高了 5-10 倍。
  • 支持字符类内的元字符 \W \D \S。
  • 在字符类内添加了元字符 \h \H \v \V。
  • 支持命名组:(?P<name>regex),以及对命名组的反向引用:(?P=name)。
  • 支持非捕获组:(?:regex)。
  • 支持前瞻,正前瞻+负前瞻:foo(?=bar), foo(?!bar), (?<=foo)bar, (?<!foo)bar。
  • 支持原子组:(?>foo|bar)。
  • 支持占有量词:a++, a*+, a?+, a{n,m}+。
  • 支持 Unicode 类别:\pL \p{L} \p{Lu},带有否定 \P。
  • 支持控制转义序列:\cA ... \cZ。
  • 支持递归:(?R) 和 (?0)。
  • 支持子程序调用:(?1) ... (?80),以及对命名组的调用:(?P>name)。
  • 添加了 FastUnicodeData 定义,它使用额外的数组来加速 Unicode 模式下的 Unicode 函数。添加了 regexpr_unicodedata 单元。
  • 添加了向后搜索的可能性(ABackward 参数)。
  • 添加了在不前进到下一个位置的情况下在单个偏移量处测试正则表达式的可能性(ATryOnce 参数)。
  • 支持 NULL 字符,既在正则表达式中也在输入字符串中。
  • 支持大于 U+FFFF 的 Unicode,即表情符号。点、\W、\S、\D 等现在应该能够正确地为 1 个表情符号找到 2 个 WideChars。
  • 添加了 \z,更改了 \Z 的行为以与主要引擎一致。

2023 年的改进

在 2023 年,Martin Friebe(SynEdit 维护者)进行了许多很好的更改。

这些更改也已合并到 FPC TRegExpr 分支中。

  • 添加了 \K(从左截断匹配)。
  • 添加了 \G 以供 ExecNext 匹配上一个匹配结束的位置。
  • 添加了完整的正向前瞻支持。添加了完整的固定长度反向前瞻支持。添加了有限的可变长度反向前瞻支持。
  • 添加了 (?modifier:pattern) 支持。
  • 添加了“属性 AllowBraceWithoutMin”以允许 {,2} 而不是 {0,2}。
  • 添加了“属性 AllowLiteralBraceWithoutRange”以允许在没有后续范围时将“{”作为字面量匹配。
  • 优化,检测更多锚点:^ $ \G .*
  • 修复了“atomic”组。允许回溯整个组。
  • 移除了嵌套循环的“LoopStackMax = 10”限制。

来自 Alexey Torgashin 的贡献:

  • 添加了 \R 支持(任何换行符)。

替换时更改大小写

您可以更改找到的片段的大小写,在替换字段中使用修饰符(大小写更改在修饰符位置之后生效):

  • \l - 将第一个字符转换为小写
  • \L - 将所有字符转换为小写
  • \u - 将第一个字符转换为大写
  • \U - 将所有字符转换为大写

例如,如果找到了一个单词,使用替换字段 "\L$0" 将单词转换为小写(这里 $0 是组 0,即找到的文本)。

此外,\n 将被替换为换行符(LF 或 CR LF,这取决于内部常量)。

示例

使用 TRegExpr 检查字符串中是否存在表达式非常简单,只需创建 TRegExpr 的一个实例,然后将您的正则表达式放入 TRegExpr.Expression 属性中,并使用 Exec 方法来验证该正则表达式是否有任何匹配项。如果表达式与传递给它的字符串匹配,Exec 将返回 true。

var
  RegexObj: TRegExpr;
begin
  RegexObj := TRegExpr.Create;
  RegexObj.Expression := '.*login.*';
  if RegexObj.Exec('Please try to login here') then WriteLn('The login was found!');
  RegexObj.Free;
end;

子表达式匹配:

program Project1;

uses
  RegExpr;

var
  re: TRegExpr;
begin
  re := TRegExpr.Create('hello (.*?)!');
  if re.Exec('hello world! hello pascal!') then
  begin
    WriteLn(re.Match[1]);
    while re.ExecNext do
    begin
      WriteLn(re.Match[1]);
    end;
  end;
  re.Free;
end.

输出:

world
pascal

FLRE - 快速轻量级正则表达式

FLRE(Fast Light Regular Expressions)是一个快速、安全且高效的正则表达式库,它使用Object Pascal(Delphi和Free Pascal)实现,但也可以从其他语言如C/C++等中使用。它能够处理Unicode和UTF-8字符串。

它实现了许多最常见的Perl和POSIX特性,除了像前向引用和嵌套反向引用等不规则表达式特性,这些在FLRE中不受支持,只支持真正的"反向引用",这也是FLRE名称中“Light”一词的由来。它还查找最左最先匹配项,与Perl和PCRE相同,并能返回子匹配信息。但它还包含一个标志,用于实验性的POSIX风格的最左最长匹配行为模式。

FLRE在LGPL v2.1静态链接异常下获得许可。

GitHub仓库

示例

实现PHP的parse_url函数(基于php.js parse_url实现)

uses Classes, SysUtils, flre;

type
  RUrlParser = record
  private
    Fcomponents: array[1..13] of string;
  private
    function getComponent(aIndex: integer): string;
    procedure setComponent(aIndex: integer; const aValue: string);
  public
    function parse(const aUrl: UTF8String): boolean;
  public
    property scheme: string index 1 read getComponent write setComponent; // 例如 http
    property authority: string index 2 read getComponent;
    property userInfo: string index 3 read getComponent;
    property user: string index 4 read getComponent;
    property pass: string index 5 read getComponent;
    property host: string index 6 read getComponent;
    property port: string index 7 read getComponent;
    property path: string index 9 read getComponent;
    property directory: string index 10 read getComponent;
    property fileName: string index 11 read getComponent;
    property query: string index 12 read getComponent; // 问号(?)之后
    property fragment: string index 13 read getComponent; // 井号(#)之后
  end;

implementation

function RUrlParser.getComponent(aIndex: integer): string;
begin
    Result := Fcomponents[aIndex];
end;

procedure RUrlParser.setComponent(aIndex: integer; const aValue: string);
begin
    Fcomponents[aIndex] := aValue;
end;

function RUrlParser.parse(const aUrl: UTF8String): boolean;
var
    i: integer;
    re: TFLRE;
    parts: TFLREMultiStrings;
begin
    re := TFLRE.Create(
      '(?:([^:\\/\?#]+):)?'
      + '(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?'
      + '()'
      + '(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\?([^#]*))?(?:#(.*))?)'
      , [rfUTF8]
    ); 

    parts := nil;
    Result := re.UTF8ExtractAll(aUrl, parts);
    if Result then
    begin
        for i := 1 to Length(parts[0]) - 1 do
        begin
            setComponent(i, string(parts[0][i]));
        end;
    end;

    // 释放正则表达式内存
    for i := 0 to Length(parts) - 1 do
    begin
        SetLength(parts[i], 0);
    end;
    parts := nil;

    re.Free();
end;

Joost的Regexpr

Joost的Regexpr(单元为oldregexpr.pp和regex.pp)是一个非常基本的正则表达式单元,它处理大多数正则表达式,类似于GNU regexpr。

当前的单元还远未完成,仍然缺少对POSIX或更复杂的语法如Perl regexJava RegexRuby Regex等的非常简单的语法支持。

该单元目前包含4个函数:

  • GenerateRegExprEngine – 编译正则表达式模式。
  • RegExprPos – 在给定字符串中查找模式。
  • DestroyRegExprEngine – 释放模式编译结果
  • RegExprEscapeStr – 转义正则表达式语言的保留语法,以便将其理解为字符串而不是正则表达式语法。

还有一个测试:

  • testreg1测试程序演示了支持的正则表达式。

Florian的Regexpr

这是最早的实现。它存在于packages/regexpr/src/old中,并且当前不被makefile编译,因此在发布的FPC/Lazarus版本中默认不可用预编译版本。