如何在Python中解析与模式匹配但跳过另一个模式的字符串

如何在Python中解析与模式匹配但跳过另一个模式的字符串,python,regex,Python,Regex,我对python的正则表达式模块及其正确用法有一些问题 让我们假设有以下字符串: string = """ ---start_skip ---start_keep1 some data ---end_keep ---end_skip ---start_keep2 some other data ---end_keep """" 我可以简单地解析keep数据 import re keep_re = re.compile(r"---start_keep(.*?)---end_keep",re.D

我对python的正则表达式模块及其正确用法有一些问题

让我们假设有以下字符串:

string = """
---start_skip
---start_keep1
some data
---end_keep
---end_skip

---start_keep2
some other data
---end_keep
""""
我可以简单地解析keep数据

import re
keep_re = re.compile(r"---start_keep(.*?)---end_keep",re.DOTALL)
for match in re.finditer(keep_re,string):
  data = match.group()
但是,我不知道如何跳过包含在--start\u skip/--end\u skip标记中的所有--start\u keep/--end\u keep子字符串。事实上,我的代码段还与--start\u keep1/-end\u keep块匹配,在我看来,它应该受到--start\u skip/-end\u skip标记的保护

有人能帮我吗

编辑:

在我的生产问题中,我有更多的问题:

在运行时更改的skip regex没有固定的长度;不能使用负匹配; skip regex包含在捕获组中,因为在其他上下文中它不是skip regex,而是keep regex! 下面是一个更接近生产问题的示例:

import re
keep_re = re.compile(r"(?P<keep>---start_keep(?P<data>.*?)---end_keep)",re.DOTALL)
skip_re = re.compile(r"(?P<skip>[`]{3}.*?[`]{3})",re.DOTALL)   
如果我按照建议使用|运算符,我将面临捕获跳过。目前,我正在努力使其不使用?:,但我没有成功:-

更清楚地说,我想做的第一件事是替换所有不受skip标记保护的keep数据

非常脏的解决方案:

亲爱的各位

我目前的生产解决方案是非常肮脏的,因此我喜欢显示它,以便阅读您的批评

我编写了以下小类方法:

def strip(self,source):
  """Method for striping raw data from source.

  Parameters
  ----------
  source : str
    string (as single stream) containing the source

  Returns
  -------
  str
    source without the raw data
  """
  if self.skip:
    strip_source = source
    pattern = '|'.join([ skip.pattern for skip in self.skip ])
    regex = re.compile(pattern+r"|(?P<strip>"+self.regex.pattern+r")",re.DOTALL)
    matches = []
    for match in re.finditer(regex,strip_source):
      if match.group('strip'):
        matches.append([match.start(),match.end()])
    if len(matches)>0:
      strip = ''
      for mtc,match in enumerate(matches):
        if mtc == 0:
          start = 0
        else:
          start = matches[mtc-1][1]+1
        if match[0]!=start:
          strip += strip_source[start:match[0]-1]
      if matches[-1][1]<len(strip_source):
        strip += strip_source[matches[-1][1]+1:]
      strip_source = strip
  else:
    strip_source = re.sub(self.regex,'',source)
  return strip_source.strip()
其中,对于skip | keep regex的每个匹配,我检查keep在方法中是否命名为strip,因为它是strip方法。。。是一个匹配的,以防万一,我管理它在这种情况下,我脱掉它。我必须首先存储开始/结束匹配字符,以便在第二段中删除它们。。。请注意,skip | keep regex很复杂,因为我可以有一个skip容器列表

欢迎提出任何建议,无论如何谢谢您的帮助

---start_skip.*?---end_skip|---start_keep\d+(.*?)---end_keep
试试这个。这将为您提供所需的部件。请参阅演示


使用一个负回溯来匹配从开始到保持的顺序,该顺序前不会立即加上“开始”\u skip

使用捕获组捕获中间字符

(?<!---start_skip\n)---start_keep\d+\n(.*?)---end_keep
解决方案 我的解决方案有点长:

(?m)^(?:---start_skip\n(?:(?!---end_skip\n)[^\n]*\n)*---end_skip|(?!---start_keep)[^\n]*\n)*---start_keep[^\n]*\n((?:(?!---end_keep)[^\n]*\n)*)---end_keep
使用前,请阅读假设部分

虽然它可以从这样的测试用例中正确地挑出匹配项:

data
---start_skip

data

---start_keep1
some data

---end_keep

more data
---end_skip

whoknows

---start_keep2
sdff
some other data
---end_keep

less data

---start_keep2

---end_keep
---start_keep2
---end_keep
---start_skip
dsfsdf
---start_keep
---end_keep
dsfdsf

---start_keep


---end_keep

---end_skip

sdfsdf

---start_keep2

werewrewrewrewrewrwewrew,,[p.[

sdfdsf

wer;[we;

---end_keep
假设 假设前面的keep或skip部分在遇到--start skip时已关闭,那么--start_skip和最近的--end_skip之间的所有内容都将被忽略。因此,没有嵌套的节。 假设前面的keep或skip部分在遇到--start keep时已关闭,那么--start_keep和最近的--end_keep之间的所有内容都将被视为要保留的文本。因此,没有嵌套的节。 当找到开始标记但未找到相应的结束标记时,行为未定义

行为未定义的示例:

---start_skip
---start_keep
something
---end_keep
如果输入在一行中有许多--start_keep,而没有任何--end_keep,则正则表达式的性能将很差,即使只添加了少量的?m^

解释
“m^part”用于在数据末尾不遇到任何keep节时减少不必要的工作,还用于忽略行中间的节标记。

您的预期输出是什么?您是否尝试使用match.group1而不是match.group?非常感谢您的帮助,但我想要的是匹配其他数据,而不是匹配其他数据data@szaghi如果答案符合您的解释,请不要忘记将其标记为正确:非常感谢,事实上,我不需要跳过--start\u keep之后的数字,这样我就可以在匹配组之前删除\d+。但是,我可以问您更多的解释吗?|运算符执行魔术,在这种情况下它是如何工作的?它应该是or运算符,因此我认为它也匹配一些数据,但它是有效的…也许魔法在于第一个备选方案的非匹配组,而第二个备选方案有一个匹配组?非常感谢您的帮助。您的贡献非常有趣。但是我有一个问题:为什么不使用简单的。*?对于--start\u skip/--end\u skip的内容?我没有必要跟踪断线,我的字符串是流块……SZAGHI:它有点强,从某种意义上说,没有有效的跳过标记可以作为中间的某条线出现。一个简单的问题?允许后端跳过在回溯中出现在中间。我还假设标记只有在行的开头才有效——这就是所有复杂性的原因。因为你没有给出所有的信息,我不得不假设写一些正则表达式。好的,谢谢你的解释。事实上,我并不要求标签只有在行首才有效。不管怎样,你的贡献是有帮助的,你是对的,负面的表情是我尝试过的第一个解决方案,但我没有做好。。。您的解决方案非常清楚,非常感谢@szaghi在这种情况下它将不起作用,也不用担心,在我的正则表达式中,我不检查换行符。再次谢谢你
in@szaghi即使后面有一个空格也会破坏这种模式。我知道,您的正则表达式非常好,例如我发布的标记之间用分隔符分隔的示例\n。事实上,我的生产问题比我发布的问题更复杂,因此我根本无法使用您的方法,但我发布的内容很好,我从中学到了很多。目前我不得不使用|运算符,因为我的实际skip regex没有固定的维度,因此我不能使用负lookback
data
---start_skip

data

---start_keep1
some data

---end_keep

more data
---end_skip

whoknows

---start_keep2
sdff
some other data
---end_keep

less data

---start_keep2

---end_keep
---start_keep2
---end_keep
---start_skip
dsfsdf
---start_keep
---end_keep
dsfdsf

---start_keep


---end_keep

---end_skip

sdfsdf

---start_keep2

werewrewrewrewrewrwewrew,,[p.[

sdfdsf

wer;[we;

---end_keep
---start_skip
---start_keep
something
---end_keep
(?m)^                              # Start matching from beginning of a line
(?:
  ---start_skip\n                  # Match skip section
  (?:(?!---end_skip\n)[^\n]*\n)*   # Take all lines in between skip section
  ---end_skip
  |
  (?!---start_keep)[^\n]*\n        # Not valid skip section. Match text until start_keep
)*                                 # Can be many skip sections and text until keep section
---start_keep[^\n]*\n              # Match keep section
((?:(?!---end_keep)[^\n]*\n)*)     # Capture text in between keep section
---end_keep