繁体   English   中英

正则表达式遵循模式,大括号之间除外

[英]Regex to follow pattern except between braces

我很难找出一个干净的正则表达式(在 Javascript 实现中),它将尽可能多地捕获一条线,因为它可以遵循一个模式,但是大括号内的任何东西都不需要遵循这个模式。 我不确定最好的解释方式,除了举例:

例如:假设模式是,行必须以 0 开头,在任何地方以 0 结尾,但只允许其间有 1、2 或 3 的序列,所以我使用^(0[123]+0) 这应该匹配字符串的第一部分:


    0213123123130
    012312312312303123123
    01231230123123031230
    etc.

但我希望能够在大括号之间插入{gibberish}并让正则表达式允许它破坏模式。 即,忽略花括号的模式和里面的所有内容,但仍然捕获包括{gibberish}在内的完整字符串。 所以这将以粗体捕获所有内容:


    01232231{whatever 3 gArBaGe? I want.}121{foo}2310312{bar}3120123

即使模式正确,大括号内的 0 也不会过早结束捕获。


    01213123123123{21310030123012301}31231230123

编辑:现在,我知道我可以做类似^0[123]*?(?:{.*})*?[123]*?0的事情吗? 但这只有在有一组大括号时才有效,现在我必须复制我的[123]模式。 随着[123]模式变得越来越复杂,让它在正则表达式中出现不止一次开始变得非常难以理解。 最好的正则表达式技巧之类的东西似乎很有希望,但我不知道如何在这里应用它。 使用疯狂的环视似乎是现在唯一的方法,但我希望有一种更清洁的方法。

由于您已指定要包括垃圾在内的整个匹配项,因此您可以使用^0([123]+(?:{[^}]*}[123]*)*)0并使用 $1 来获取部分在 0 之间,或 $0 以获得匹配的所有内容。

https://regex101.com/r/iFSabs/3

以下是正则表达式如何工作的概要:

  • ^将匹配锚定在行首
  • 0匹配文字零字符
  • ([123]+(?:{[^}]*}[123]*)*)是一个捕获组,它捕获其中的所有内容。
    • [123]+匹配123的一个或多个实例
    • (?:{[^}]*}[123]*)*是一个非捕获组。 即它将成为比赛的一部分,但不会有 $# 用于替换或比赛。
      • {[^}]*}匹配文字{后跟任意数量的非}字符后跟 }
      • [123]*匹配123的零个或多个实例
      • 那么这整个非捕获组可以匹配0次或多次。

此正则表达式背后的过程称为展开循环。 http://www.softec.lu/site/RegularExpressions/UnrollingTheLoop给出了很好的描述。 (有一些错字修复)

展开循环技术是基于这样一个假设,即在大多数情况下,您会 [知道] 在 [重复] 交替中,哪种情况应该是最常见的,哪种情况是例外的。 我们将第一个称为正常情况,将第二个称为特殊情况。 展开循环技术的一般语法可以写成:

正常*(特殊正常*)*

这可能意味着类似,匹配正常情况,如果你找到一个特殊情况,匹配它而不是再次匹配正常情况。 [你会]注意到这个语法的一部分可能[潜在地]导致超线性匹配。

使用 Regex#test 和 Regex#match 的示例:

 const strings = [ '0213123123130', '012312312312303123123', '01231230123123031230', '01213123123123{21310030123012301}31231230123', '01212121{hello 0}121312', '012321212211231{whatever 3 gArBaGe? I want.}1212313123120123', '012321212211231{whatever 3 gArBaGe? I want.}121231{extra garbage}3123120123', ]; const regex = /^0([123]+(?:{[^}]*}[123]*)*)0/ console.log('tests') console.log(strings.map(string => `'${string}': ${regex.test(string)}`)) console.log('matches'); let matches = strings.map((string) => regex.exec(string)).map((match) => (match? match[1]: undefined)); console.log(matches);

Robo Robok 的答案是 go 如果您只想保留非支撑部分,尽管使用稍微不同的正则表达式( {[^}]*} )以获得更高的性能。

反过来呢? 检查删除了卷曲标签的字符串:

const string = '012321212211231{whatever 3 gArBaGe? I want.}1212313123120123{foo}123';
const stringWithoutTags = string.replace(/\{.*?\}/g, '');

const result = /^(0[123]+0)/.test(stringWithoutTags);

您说您需要捕获所有内容,包括乱码,所以我认为像这样的简单模式应该可以工作:

^(0(?:[123]|{.+?})+0)

这允许以 0 开头的字符串,然后是任何模式字符(1、2 或 3){ gibberish }部分之一,并允许重复处理多个乱码部分,最后它必须以一个 0。

https://regex101.com/r/K4teGY/2

你可能会使用

^0[123]*(?:{[^{}]*}[123]*)*0
  • ^字符串开头
  • 0匹配一个零
  • [123]*匹配 0+ 次 1、2 或 3
  • (?:非捕获组
    • {[^{}]*}[123]*匹配从开始到结束}后跟 0+ 1、2 或 3
  • )*关闭组并重复 0+ 次
  • 0匹配一个零

正则表达式演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM