【问题标题】:PCRE Regex: Is it possible to check within only the first X characters of a string for a matchPCRE Regex:是否可以仅在字符串的前 X 个字符内检查匹配项
【发布时间】:2021-01-27 00:32:41
【问题描述】:

PCRE 正则表达式:正则表达式是否可以仅在字符串的前 X 个字符内检查模式匹配,而忽略该点之后字符串的其他部分?

我的正则表达式:

我有一个正则表达式:

/\S+V\s*/

这会检查字符串中是否有尾随“V”和空格字符或字符串结尾的非空白字符。

这行得通。例如:

示例 A:

 SEBSTI FMDE OPORV AWEN STEM students into STEM 

// Match found in 'OPORV' (correct)

示例 B:

 ARKFE SSETE BLMI EDSF BRNT CARFR (name removed) Academy Networking Event 
      
//Match not found (correct).   

Re:每个字母的大写文本和字母位置在源数据中都有含义。接下来是供人类阅读的通用信息(“学院网络活动”等)

我的问题:

理论上有时会出现一些名称涉及罗马数字,例如:

示例 C:

 ARKFE SSETE BLME CARFR Academy IV Networking Event 
      
//Match found (incorrect).  

我希望我上面的正则表达式只检查字符串的前 X 个字符。

这可以在 PCRE Regex 本身中完成吗?我在正则表达式中找不到任何长度计数的参考,我怀疑这不容易实现。字符串长度是完全任意的。 (我们无法控制源数据)。

意图:

/\S+V\s*/{check within first 25 characters only}
 ARKFE SSETE BLME CARFR Academy IV Networking Event 
                         ^
                         \-  Cut off point. Not found so far so stop. 

//Match not found (correct).  

解决方法:

正则表达式在 PHP 中,我目前的解决方案是在 PHP 中剪切字符串,只检查前 X 个字符,通常是前 20 个字符,但我很好奇是否有办法在正则表达式中做到这一点而无需需要直接在 PHP 中操作字符串?

$valueSubstring = substr($coreRow['value'],0,20); /* first 20 characters only */
$virtualCount = preg_match_all('/\S+V\s*/',$valueSubstring); 

【问题讨论】:

  • 您的“解决方法”听起来是最简单的方法,而且可能是任何人都会推荐的。找到一种仅使用正则表达式的方法可能会使正则表达式更难理解。
  • @HernánAlarcón 绝对是,但我很好奇,因为我从未见过任何正则表达式引用仅搜索字符串的子部分。
  • 如果你坚持,我猜你可以在匹配前使用积极的后视来匹配最多 25-n 个字符(长度为 n)。
  • “ARKFE SSETE BLMEV CARFR Academy IV 联谊活动”怎么样?

标签: regex pcre


【解决方案1】:

诀窍是在前瞻中捕获前 25 个字符之后的行尾,并检查它是否遵循您的子模式的最终匹配:

$pattern = '~^(?=.{0,25}(.*)).*?\K\S+V\b(?=.*\1)~m';

demo

详情:

^ # start of the line

(?= # open a lookahead assertion
    .{0,25} # the twenty first chararcters
    (.*) # capture the end of the line
) # close the lookahead

.*? # consume lazily the characters

\K # the match result starts here

\S+V    # your pattern
\b      # a word boundary (that matches between a letter and a white-space
        # or the end of the string)

(?=.*\1) # check that the end of the line follows with a reference to
         # the capture group 1 content.

请注意,您还可以像这样以更易读的方式编写模式:

$pattern = '~^
    (*positive_lookahead: .{0,20} (?<line_end> .* ) )
    .*?    \K    \S+ V \b
    (*positive_lookahead: .*? \g{line_end} )   ~xm';

(替代语法 (*positive_lookahead: ...) 自 PHP 7.3 起可用)

【讨论】:

    【解决方案2】:

    您可以在 X 字符之后找到您的模式并跳过整个字符串,否则,匹配您的模式。所以,如果 X=25:

    ^.{25,}\S+V.*(*SKIP)(*F)|\S+V\s*
    

    请参阅regex demo详情

    • ^.{25,}\S+V.*(*SKIP)(*F) - 字符串开头,除换行符以外的25个或更多字符,尽可能多,然后是一个或多个非空格和V,然后是字符串的其余部分,匹配失败并跳过
    • | - 或
    • \S+V\s* - 匹配一个或多个非空白字符、V 和零个或多个空白字符。

    【讨论】:

    • 这似乎行得通。谢谢。我从来不知道(*F) 功能。
    • 奇怪的是,正则表达式链接显示 600 步,但我希望在第 25 个字符之后,这些步骤会中止(大约 60 步)
    • @GerardH.Pille 这就是目的。我只想在字符串的前 X 个字符中查找 V,在本例中为 25
    • @Martin 该模式更像是一个示意图,PoC 模式。您可以进一步改进它,例如在跳过部分,您不需要匹配所有非空格,所以使用^.{25,}\SV.*(*SKIP)(*F)|\S+V\s*
    • @WiktorStribiżew 啊哈,我错过了修复它的/m。再次感谢您的建议:-)
    【解决方案3】:

    任何以前 25 个位置结尾的 V

    ^.{1,24}V\s
    

    regex

    前 25 个位置以 V 结尾的任何单词

    ^.{1,23}[A-Z]V\s
    

    【讨论】:

    • 我需要找到一个 V 前面有一个非空白字符,然后是一个空白字符,并且只在字符串的第一部分。这匹配字符串任何部分的大小写。
    • 您将只能找到与此模式匹配的 单个。在前 X 个字符内搜索意味着可能有多个匹配项。
    • 没有,见链接
    • @WiktorStribiżew 行匹配,正如所要求的那样。
    • 即便如此,您的模式与 OP 的模式不同。您的正则表达式 matches,例如1 V (ex) 这不是预期的。
    猜你喜欢
    • 2015-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多