Python 相当于 Perl“..”触发器运算符

问题描述 投票:0回答:3

Perl“

..
”(范围或触发器)运算符的 Python 等价物是什么?

for ( qw( foo bar barbar baz bazbaz bletch ) ) { 
    print "$_\n" if /ar.a/ .. /az\w/;
}

输出:

barbar
baz
bazbaz

我所知道的Python解决方法包括生成器表达式和借助

enumerate
的帮助进行索引,但这似乎很麻烦:

import re

lst = 'foo bar barbar baz bazbaz bletch'.split()
idx_from = list(i for i, el in enumerate(lst) if re.search(r'ar.a', el))[0]
idx_to   = list(i for i, el in enumerate(lst) if re.search(r'az\w', el))[0]

lst_subset = lst[ idx_from : (idx_to+1)]
print(lst_subset)
# ['barbar', 'baz', 'bazbaz']

注:

我只寻找一个范围。目前不需要有多个范围。

python regex range slice
3个回答
2
投票

基本(在线尝试!):

import re

in_range = False
for word in 'foo bar barbar baz bazbaz bletch'.split():
    if not in_range:
        in_range = re.search(r'ar.a', word)
    if in_range:
        print(word)
    if in_range:
        in_range = not re.search(r'az\w', word)

通过课程(在线尝试!):

import re

class Within:
    def __init__(self, flip, flop):
        self.flip = flip
        self.flop = flop
        self.state = False
    def __bool__(self):
        if not self.state and self.flip():
            self.state = True
        result = self.state
        if self.state and self.flop():
            self.state = False
        return result

within = Within(
    lambda: re.search(r'ar.a', word),
    lambda: re.search(r'az\w', word),
)
for word in 'foo bar barbar baz bazbaz bletch'.split():
    if within:
        print(word)

Itertoolsish(在线尝试!):

import re

def flipflop(iterable, flip, flop):
    state = False
    for x in iterable:
        if not state:
            state = flip(x)
        if state:
            yield x
        if state:
            state = not flop(x)

for word in flipflop(
    'foo bar barbar baz bazbaz bletch'.split(),
    re.compile(r'ar.a').search,
    re.compile(r'az\w').search
):
    print(word)

或者没有状态变量,外循环搜索元素以进入范围,内循环搜索元素以退出范围(在线尝试!):

import re

def flipflop(iterable, enter, exit):
    it = iter(iterable)
    for x in it:
        if enter(x):
            yield x
            if not exit(x):
                for x in it:
                    yield x
                    if exit(x):
                        break

for word in flipflop(
    'foo bar barbar baz bazbaz bletch'.split(),
    re.compile(r'ar.a').search,
    re.compile(r'az\w').search
):
    print(word)

1
投票

警告,因为我不知道

perl
足以理解什么
..
,我实现了类似于GNU AWK
Ranges
的东西,希望它足够接近您的用例。

据了解,没有直接等效的可用方法,因此我建议使用以下标记方式来实现此功能

import re
def get_re_range(iterable, start_pattern, end_pattern):
    flag = False
    for element in iterable:
        if re.search(start_pattern, element):
            flag = True
        if flag:
            yield element
        if re.search(end_pattern, element):
            flag = False
words = "foo bar barbar baz bazbaz bletch".split()
for word in get_re_range(words, r'ar.a', r'az\w'):
    print(word)

提供输出

barbar
baz
bazbaz

观察

if
的顺序以获得包容性行为。


1
投票

当操作数不是简单数字时,标量上下文中的

EXPR1 .. EXPR2
相当于以下内容(
do { }
创建的范围除外):

do {
   state $hidden_state = 0;
   if ( $hidden_state ) {
      ++$hidden_state;
   } else {
      $hidden_state = 1 if EXPR1;
   }

   my $rv = $hidden_state;

   # Or `$hidden_state > 1 && EXPR2` for `...`.
   if ( $hidden_state && EXPR2 ) {
      $rv .= "E0";
      $hidden_state = 0;
   }

   $rv
}

由于您只关心触发器返回 true 或 false,因此上面的内容简化为以下内容:

do {
   state $hidden_state = false;
   $hidden_state ||= EXPR1;
   my $rv = $hidden_state;
   $hidden_state &&= EXPR2;
   $rv
}

现在我们必须翻译这个。由于翻转翻转通常用作生成器,这就是我将创建的。

def flipflop( enumerable, start_cond, end_cond ):
   state = False
   for val in enumerable:
      if not state:
         state = start_cond( val )
      if state:
         yield val
      if state:
         state = end_cond( val )
import re

lst = 'foo bar barbar baz bazbaz bletch'.split()

for x in flipflop( lst, lambda v: re.search( r'ar.a', v ), lambda v: re.search( r'az\w', v ) ):
   print( x )
© www.soinside.com 2019 - 2024. All rights reserved.