当前位置: 首页 > 知识库问答 >
问题:

在任意正则表达式中插入正向look back来模拟字节偏移量的结果

凌华奥
2023-03-14

为n字节插入正后视会有什么后果,(?

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

对性能和可读性显然会有一些(姑且称之为微不足道的)后果,但是会有任何(不可忽视的)影响吗,比如匹配变成不匹配(除非它们没有偏移n个字节)或者替换变得畸形?

一些例子:

< code>/some expression/变成了< code>/(?

/(this) has (groups)/i 变为 /(?

据我所知,从我运行的有限测试来看,添加此回溯可以有效地模拟此偏移参数,并且不会弄乱任何其他回溯、替换或其他控制模式;但我也不是正则表达式的专家。

我试图确定通过在模式中插入n字节的look back来构建替换/过滤函数扩展是否有任何可能的后果。它应该像match函数的offset参数一样工作——因此,简单地对< code>substr( $subject,$offset )运行表达式是行不通的,原因与它对< code>preg_match不起作用的原因相同(最值得注意的是,它切断了任何lookbehinds,然后^错误地匹配子字符串的开头,而不是原始字符串)。

共有2个答案

谭仰岳
2023-03-14

你可以试试< code>/(?

杜禄
2023-03-14

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

\C

相当于

[\x00-\xff]

(?s:.)

它们中的任何一个都可以在后面查看中用作preg_matchpreg_match_all函数中offset字段的替换。

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

UTF模式可以通过传递给< code>preg_*函数的模式中的< code>u标志激活,或者通过在模式开头指定< code>(*UTF8)、< code>(*UTF16)、< code>(*UTF32)动词激活。

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

虽然< code>\C是专门设计来匹配一个数据单元(在UTF-8中是一个字节),而不管UTF模式是否打开,但它在UTF模式的后视构造中不受支持。

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

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

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

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

>

  • \C匹配1个数据单元,无论是UTF模式还是非UTF模式。但是,它不能在UTF模式下用于look behind。

    匹配单个数据单元

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

    <代码>在非UTF模式下匹配1个数据单元。

    关于 UTF 模式的一般评论

    [...]

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

    方括号和字符类

    [...]

    字符类匹配主题中的单个字符。在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
    

    无效的Unicode代码点范围为0xd800到0xdfff(所谓的“代理”代码点)和0xffef。

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

    要与 pcre_exec() 匹配的字符串

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

    < code>pcre_exec()如何返回捕获的子字符串

    [...]

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

  •  类似资料:
    • 是否有一种简单的方法可以使用另一个正则表达式(考虑括号内的情况)从正则表达式中删除正/负lookback/lookahead组? 示例源表达式:

    • 我肯定这已经张贴之前,但我有麻烦找到一个答案。

    • 问题内容: 据我所知,MySQL不支持从正则表达式匹配中检索捕获组的值。我发现了一个服务器端扩展(lib_mysqludf_preg),它将添加此功能,但无法在我的环境中安装此扩展。 因此,我正在寻找一种方法来模拟将正则表达式匹配的一部分捕获为SQL查询中的一列。 我的数据如下所示(并且我无法更改服务器上的数据格式): 我正在寻找每行的最后4位数字。数字始终是值的最后一部分,并且始终由点分隔。以下

    • 我需要编写一个具有以下规则的正则表达式: null null 这些示例无效: > 12--11(因为它包含两个连字符) 1-2345(因为它包含5号) <>是字符出现在最后一个位置,那么在字符之前必须有一个数字not hypen。 即11-A(必须不及格)11-1A(必须及格)

    • 我是正则表达式的初学者,并尝试搜索特定的数字模式。以下数据以 XML 格式嵌入。 要求是提取数据(最里面的列表)。在这个例子中,数据从24779开始到24760。注意:每次数据可能不是从“24”开始。因此,我计划通过以下逻辑提取:如果标签名(在本例中:DUT_1_PC)具有非零的有效数据,并且有效数据的计数大于100,用逗号分隔,则提取该列表及其标签名(DUT_1_PC)。 我无法提取所需的数据。