Search for phrase within left and right bounds

Viewed 59

It will be better if I show what I mean.

Here are some selections from a data set I am parsing:

1.【ひろゆき】万能ねぎとわけぎと記憶力。Grimbergen blondeを呑みながら。2020/12/18 V23

2.【ひろゆき】日本酒は鮮度が大事ですよ。 獺祭を呑みながら 2019/02/11

3.【ひろゆき】聞かれたことに答えてみようの回。Cheshire Chocolate Porter飲みつつ。

4.【ひろゆき】早起きは得しないし、体に悪いよね。。Lagunitas IPAを呑みながら 2019/04/14 D23

I am trying to grab the name of the beverege. In 1 it is "Grimbergen blonde", in 2 "獺祭" it is in 3 it is "Cheshire Chocolate Porter", in 4 it is "Lagunitas IPA"

I have tried using the following pattern:

pattern = re.compile('(?<=[\?。!]).*(?=を[飲呑])')

I see that the drink is always immediately followed by or / . I also see that the drink is always immediately after or .

How can this be done?

2 Answers

We can use a [|] for an or statement in our lookahead to check for either of the two following chars.

re.findall(r'(?<=。)[^。].*(?=[を|飲])', string)

#['Grimbergen blonde', ' 獺祭', 'Cheshire Chocolate Porter', 'Lagunitas IPA']

Breakdown

  1. (?<=。) - Check if occurs before our search, look behind.
  2. [^。].* - Match all excluding This accounts for the double 。。 before Lagunitas
  3. (?=[を|飲]) - Look ahead to see if any of the characters directly follow our match all

You can find a further breakdown here

[EDIT]
Would you please try the following:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import re
import sys, codecs

sys.stdout = codecs.getwriter('utf_8')(sys.stdout)

str = u"""
1.【ひろゆき】万能ねぎとわけぎと記憶力。Grimbergen blondeを呑みながら。2020/12/18 V23

2.【ひろゆき】日本酒は鮮度が大事ですよ。 獺祭を呑みながら 2019/02/11

3.【ひろゆき】聞かれたことに答えてみようの回。Cheshire Chocolate Porter飲みつつ。

4.【ひろゆき】早起きは得しないし、体に悪いよね。。Lagunitas IPAを呑みながら 2019/04/14 D23
5.【ひろゆき】冬将軍強くね?温暖化どこいったの? PARISIS NOËLを呑みつつ 2019/01/26
6.【ひろゆき】運のいい人っているよね。科学的根拠ないけど。。LA VIRGEN MADRID LAGERを呑みながら  2020/01/16 J08
"""

m = re.finditer(ur'.*[。?]+\s?(.*?)を?[呑飲]', str)
for i in m:
    print(i.group(1))

Result:

Grimbergen blonde
獺祭
Cheshire Chocolate Porter
Lagunitas IPA
PARISIS NOËL
LA VIRGEN MADRID LAGER

Explanation of the regex '.*[。?]+\s?(.*?)を?[呑飲]':

  • The first .* matches as long as possible then backtracks to try the following regex matches.
  • [。?]+ matches one or more sequence of Japanese period or question mark.
  • \s? matches a blank character if any. It removes leading white spaces before the name of the beverage.
  • The ? in the (.*?) enables the shortest (non-greedy) match and the capture group is assigned to the matched substring.
  • を? matches a character "を" if any considering the case the postpositional particle "を" is sometimes omitted in Japasene.
  • [呑飲] matches either character which are variation of Kanji meaning "to drink".

In the previous post, the leading .* was missing and allowed an excess match. Now the regex once increments the pointer as much as possible then backtracks from right to left. That is why the unnecessary substring is removed now.

Related