Python 中与 Perl“ ..”(范围或触发器)符对应的是什么?

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

输出:

barbar
baz
bazbaz

我所知道的 Python 解决方法包括借助和索引,但这看起来很麻烦:

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']

笔记:

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

6

  • 1
    我认为,最好的解决方案实际上是遍历字符串列表,使用 lambda 函数并以正则表达式作为开始和结束条件。我想不出一个好的方法来解决它。


    – 

  • 您的解决方法不正确,因为它仅找到一个范围。


    – 


  • @ikegami 我只寻找一个范围。目前不需要有多个范围。抱歉没有说清楚。我编辑了答案。


    – 

  • 以后请问 Perl 中某些东西是做什么的,或者 Python 中某些东西是如何做的。这些是完全不同的问题。


    – 


  • 1
    @ikegami 这个问题已经问的是后者,而不是前者。


    – 


最佳答案
3

基本():

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)

当操作数不是简单数字时,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
}

由于您只关心触发器返回真还是假,因此上述内容简化为以下内容:

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

现在我们必须翻译它。由于 flip-flip 通常用作生成器,所以我将创建它。

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 )

7

  • 添加翻译


    – 

  • … 略有不同。我认为只是$hidden_state > 1 && EXPR2相反?


    – 

  • 哦,我忘了,抱歉


    – 

  • 是的,...可以这样实现。


    – 

  • 2
    -1 的依据是什么…?如果有人能解释一下那就太好了


    – 


警告,由于我perl对理解..我实现的类似于GNU 的AWK东西还不够了解,希望它足够接近您的用例。

据我所知,没有直接的等效方法,因此我建议使用以下方式使用标志来实现

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

观察ifs 的顺序以获得包含-包含行为。