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

时间:2014-11-28 07:29:04

标签: php regex regex-lookarounds

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

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

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

一些例子:

对于4字节偏移量

/some expression/变为/(?<=\C{4})some expression/

对于2字节的偏移量,

/(this) has (groups)/i变为/(?<=\C{2})(this) has (groups)/i

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

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

2 个答案:

答案 0 :(得分:6)

简短回答

在非UTF模式下,UTF-8库

假设与PHP捆绑在一起的PCRE库编译为 8位库(UTF-8),则在非UTF模式下

\C

相当于

[\x00-\xff]

(?s:.)

其中任何一个都可以在后视中用作offsetpreg_match函数中preg_match_all字段的替换。

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

在UTF模式下,UTF-8库

UTF模式可以通过传递给u函数的模式中的preg_*标记激活,也可以通过指定(*UTF)(*UTF8)(*UTF16),{{ 1}}动词在模式的开头。

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

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

UTF-16和UTF-32库

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

更多细节

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

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

正则表达式构造

在非UTF模式下,字符类preg_*,点[].恰好匹配1个数据单元。

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

      

    匹配单个数据单元

         

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

  • \C在非UTF模式下匹配1个数据单元。

      

    关于UTF模式的一般评论

         

    [...]

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

      

    SQUARE BRACKETS和CHARACTER CLASSES

         

    [...]

         

    字符类匹配主题中的单个字符。在UTF中     模式,该字符可能不止一个数据单元。

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

      

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

    \x{hh...}
         

    无效的Unicode代码点是0xd800到0xdfff的范围(所以 -      叫&#34;代理&#34;代码点)和0xffef。

偏移

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

  

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

匹配的字符串      

主题字符串作为pcre_exec()中的指针传递给pcre_exec(),a          subject中的长度和length中的起始偏移量。单位为          startoffsetlength是8位库的字节,即16位数据          16位库的项目和32位的32位数据项          库。

  

startoffset如何返回捕获的子字符串

     

[...]

     

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

答案 1 :(得分:1)

您可以尝试/(?<=[\x00-\xFF]{n})some expression/获取'n' - byte偏移量。添加锚点或其他一些开始对齐的软锚。