将正反面插入任意正则表达式以模拟字节偏移的后果

Bri*_*rth 10 php regex regex-lookarounds

将n个字节的正向lookbehind插入(?<=\C{n})任意正则表达式的开头会有什么后果,特别是在用于替换操作时?

至少在PHP中,正则表达式匹配函数,preg_matchpreg_match_all允许匹配在给定的字节偏移之后开始.在任何其他PCRE PHP函数中没有相应的功能 - 例如,您可以指定对替换次数的限制preg_replace,但不能指定那些替换的匹配必须在n个字节之后发生.

显然会有一些(让它们称之为微不足道)对性能和可读性产生影响,但是会有任何(非平凡的)影响,比如匹配变为不匹配(除非它们没有被n个字节偏移)或者替换变得格格不入?

一些例子:

/some expression/成为/(?<=\C{4})some expression/一个4字节的偏移量

/(this) has (groups)/i成为/(?<=\C{2})(this) has (groups)/i2字节的偏移量

据我所知,并且从我运行的有限测试中,添加这个lookbehind有效地模拟了这个偏移参数,并且不会混淆任何其他的lookbehinds,替换或其他控制模式; 但我也不是Regex的专家.

我试图通过将n字节lookbehind插入模式来确定是否有可能对构建替换/过滤器​​函数扩展产生影响.它应该像匹配函数的偏移参数一样工作 - 因此简单地运行表达式substr( $subject, $offset )将不会出于与其不相同的原因preg_match(最明显的是它会切断任何外观,^然后错误地匹配子字符串的开头,不是原来的字符串).

nha*_*tdh 6

简短的回答

在非UTF模式下,UTF-8库

假设您的PHP捆绑的PCRE库被编译为8位库(UTF-8),那么在非UTF模式下

\C
Run Code Online (Sandbox Code Playgroud)

相当于

[\x00-\xff]
Run Code Online (Sandbox Code Playgroud)

(?s:.)
Run Code Online (Sandbox Code Playgroud)

它们中的任何一个都可以在后视中用作offset现场preg_matchpreg_match_all功能的替代品.

在非UTF模式下,它们都匹配1个数据单元,即8位(UTF-8)PCRE库中的1个字节,它们匹配所有256个可能的不同值.

在UTF模式下,UTF-8库

UTF模式可以通过激活u标志传递给图案preg_*的功能,或者通过指定(*UTF),(*UTF8),(*UTF16),(*UTF32)在模式的始动词.

在UTF模式下,字符类[]和点元字符.将匹配Unicode字符的有效范围内的一个代码点,而不是代理项.由于UTF-8中的一个代码点可以编码为1到4个字节,并且由于UTF-8的编码方案,因此不可能使用字符类构造来匹配0x80到0xFF范围内的值的单个字节.

虽然\C专门设计为匹配一个数据单元(UTF-8中的一个字节),无论UTF模式是否打开,但在UTF模式下的后视构造中不支持它.

UTF-16和UTF-32库

我不知道是否有人实际编译16位或32位PCRE库,将其包含在PHP库中并实际使其工作.如果有人知道这种构建在野外广泛使用,请ping我.我实际上不知道如何将PHP的字符串和偏移量传递给PCRE的C API,具体取决于preg_*函数的结果可能有所不同.

更多细节

在PCRE库的C API级别,您只能使用数据单元,对于8位库为8位单元,对于16位库为16位单元,对于32位库为32位单元.

对于8位库(UTF-8),1个数据单元是8位或1个字节,因此指定偏移量(无论是作为参数还是作为正则表达式构造)都没有太大的障碍.

正则表达式构造

在非UTF模式下,字符类[],点.\C正好匹配1个数据单元.

  • \C匹配1个数据单元,无论是UTF模式还是非UTF模式.但它不能用于UTF模式的后视.

    匹配单个数据单元

    在字符类之外,转义序列\C匹配任何一个数据单元,无论是否设置了UTF模式.

  • . 在非UTF模式下匹配1个数据单元.

    关于UTF模式的一般评论

    [...]

    1. 点元字符匹配一个UTF字符而不是单个数据单元.
  • 字符类在非UTF模式下匹配1个数据单元.文档没有明确说明这一点,但措辞暗示了这一点.

    SQUARE BRACKETS和CHARACTER CLASSES

    [...]

    字符类匹配主题中的单个字符.在UTF模式下,字符可以是多于一个数据单元.

    通过查看\x{hh...}语法的上限可以达到相同的结论,以在非UTF模式下通过十六进制代码指定字符.通过测试,关于代理的最后一个条款似乎不适用于非UTF模式.

    使用八进制或十六进制数字指定的字符仅限于某些值,如下所示:

     8-bit non-UTF mode    less than 0x100
     8-bit UTF-8 mode      less than 0x10ffff and a valid codepoint
     16-bit non-UTF mode   less than 0x10000
     16-bit UTF-16 mode    less than 0x10ffff and a valid codepoint
     32-bit non-UTF mode   less than 0x100000000
     32-bit UTF-32 mode    less than 0x10ffff and a valid codepoint
    
    Run Code Online (Sandbox Code Playgroud)

    无效的Unicode代码点是范围0xd800到0xdfff(所谓的"代理"代码点)和0xffef.

抵消

提供和返回的所有偏移量均以数据单位数量表示:

要匹配的字符串 pcre_exec()

主题字符串pcre_exec()作为指针传入subject,长度为in length,起始偏移量为startoffset. 8位库的单位 lengthstartoffset字节数,16位库的16位数据项和32位库的32位数据项.

如何pcre_exec()返回捕获的子串

[...]

当匹配成功时,有关捕获的子串的信息将以整数对的形式返回,从ovector的开头开始,最多持续长度的三分之二.每对中的第一个元素设置为子字符串中第一个字符的偏移量,第二个元素设置为子字符串结尾后第一个字符的偏移量.即使在UTF模式下,这些值也始终是数据单元偏移量.