Python Regex - Get strings before and after substring - python

import re
txt = '<li>one. URL : http://local.ru (10.02.2022).</li><li>Two</li><li>Three. URL : https://local.ru (15.11.2021).</li>'
re.findall(r'(<li>.*?)\s?URL\s?:\s?(<a.*?>).*?(</a>.*?</li>)', txt)
I need gen output
[('<li>one.', '', ' (10.02.2022).</li>'),
('<li>Three.', '', ' (15.11.2021).</li>')]
If without the first brackets, then it works. But it does not output the text

Seems like your regex was too generous on the .*?, if you limit to non-node with [^<>], then you get the expected output.
import re
txt = (
'<li>one. URL : http://local.ru (10.02.2022).</li>'
'<li>Two</li>'
'<li>Three. URL : https://local.ru (15.11.2021).</li>'
)
re.findall(r"(<li>[^<>]*?)\s?URL\s?:\s?(<a[^>]*?>).*?(</a>.*?</li>)", txt)
gives
[('<li>one.', '', ' (10.02.2022).</li>'),
('<li>Three.', '', ' (15.11.2021).</li>')]

Related

Python extract all substrings between character and another string

Similar questions out there, but my use case is to extract all substrings that exist between a marker and another string that also includes a '(', which seems to be throwing off regex. Like this-
qry_text -
with
qry_1 as ( qry text)
,
qry_2 as (qry text)
I'd like to extract all subqueries with something like extract between ' ' and 'as ('
re.findall(r'''(.+?)as (',qry_text)
To get -
qry_1,qry2
Regex is not well understood to me, so any suggestions are appreciated.
Maybe named groups in regex can bring you some handy features:
import re
input_str = """with
qry_1 as ( qry text)
,
qry_2 as (qry text)"""
for text in input_str.splitlines():
match = re.search(r'(?P<query>^.*?) as \((?P<text>.*?)\)', text)
if match:
print(match.groupdict())
# {'query': 'qry_1', 'text': ' qry text'}
# {'query': 'qry_2', 'text': 'qry text'}

Parse sentences with [value](type) format

I want to parse and extract key, values from a given sentence which follow the following format:
I want to get [samsung](brand) within [1 week](duration) to be happy.
I want to convert it into a split list like below:
['I want to get ', 'samsung:brand', ' within ', '1 week:duration', ' to be happy.']
I have tried to split it using [ or ) :
re.split('\[|\]|\(|\)',s)
which is giving output:
['I want to get ',
'samsung',
'',
'brand',
' within ',
'1 week',
'',
'duration',
' to be happy.']
and
re.split('\[||\]|\(|\)',s)
is giving below output :
['I want to get ',
'samsung](brand) within ',
'1 week](duration) to be happy.']
Any help is appreciated.
Note: This is similar to stackoverflow inline links as well where if we type : go to [this link](http://google.com) it parse it as link.
As first step we split the string, and in second step we modify the string:
s = 'I want to get [samsung](brand) within [1 week](duration) to be happy.'
import re
s = re.split('(\[[^]]*\]\([^)]*\))', s)
s = [re.sub('\[([^]]*)\]\(([^)]*)\)', r'\1:\2', i) for i in s]
print(s)
Prints:
['I want to get ', 'samsung:brand', ' within ', '1 week:duration', ' to be happy.']
You may use a two step approach: process the [...](...) first to format as needed and protect these using some rare/unused chars, and then split with that pattern.
Example:
s = "I want to get [samsung](brand) within [1 week](duration) to be happy.";
print(re.split(r'⦅([^⦅⦆]+)⦆', re.sub(r'\[([^][]*)]\(([^()]*)\)', r'⦅\1:\2⦆', s)))
See the Python demo
The \[([^\][]*)]\(([^()]*)\) pattern matches
\[ - a [ char
([^\][]*) - Group 1 ($1): any 0+ chars other than [ and ]
]\( - ]( substring
([^()]*) - Group 2 ($2): any 0+ chars other than ( and )
\) - a ) char.
The ⦅([^⦅⦆]+)⦆ pattern just matches any ⦅...⦆ substring but keeps what is in between as it is captured.
You could replace the ]( pattern first, then split on [) characters
re.replace('\)\[', ':').split('\[|\)',s)
One approach, using re.split with a lambda function:
sentence = "I want to get [samsung](brand) within [1 week](duration) to be happy."
parts = re.split(r'(?<=[\])])\s+|\s+(?=[\[(])', sentence)
processTerms = lambda x: re.sub('\[([^\]]+)\]\(([^)]+)\)', '\\1:\\2', x)
parts = list(map(processTerms, parts))
print(parts)
['I want to get', 'samsung:brand', 'within', '1 week:duration', 'to be happy.']

How to allow characters and whitespaces in an exception in regex?

Given the input:
1993年8月にデビュー。。。同年11月から1995年3月にかけてクラシック三冠を含むGI5連勝、10連続連対を達成し、1993年JRA賞最優秀3歳牡馬[† 3]、1994年JRA賞年度代表馬および最優秀4歳牡馬[† 3]に選出された。1995年春に故障(股関節炎)を発症したあとはその後遺症から低迷し、6戦して重賞を1勝するにとどまった(GI は5戦して未勝利)が、第44回阪神大賞典におけるマヤノトップガンとのマッチレースや短距離戦である第26回高松宮杯への出走によってファンの話題を集めた。第26回高松宮杯出走後に発症した屈腱炎が原因となって1996年10月に競走馬を引退した。競走馬を引退したあとは種牡馬となったが、1998年9月に胃破裂を発症し、安楽死の措置がとられた。
Desired output is:
["1993年8月にデビュー。"
"同年11月から1995年3月にかけてクラシック三冠を含むGI5連勝、", "10連続連対を達成し、",
"1993年JRA賞最優秀3歳牡馬[† 3]、", "1994年JRA賞年度代表馬および最優秀4歳牡馬[† 3]に選出された。",
"1995年春に故障(股関節炎)を発症したあとはその後遺症から低迷し、", "6戦して重賞を1勝するにとどまった",
"(GI は5戦して未勝利)が、", "第44回阪神大賞典におけるマヤノトップガンとのマッチレースや短距離戦である第26回高松宮杯への出走によってファンの話題を集めた。",
"第26回高松宮杯出走後に発症した屈腱炎が原因となって1996年10月に競走馬を引退した。",
"競走馬を引退したあとは種牡馬となったが、", "1998年9月に胃破裂を発症し、", "安楽死の措置がとられた。"]
I've tried the following regex:
import re
text= str("1993年8月にデビュー。"
"同年11月から1995年3月にかけてクラシック三冠を含むGI5連勝、10連続連対を達成し、"
"1993年JRA賞最優秀3歳牡馬[† 3]、1994年JRA賞年度代表馬および最優秀4歳牡馬[† 3]に選出された。"
"1995年春に故障(股関節炎)を発症したあとはその後遺症から低迷し、6戦して重賞を1勝するにとどまった"
"(GI は5戦して未勝利)が、第44回阪神大賞典におけるマヤノトップガンとのマッチレースや短距離戦である第26回高松宮杯への出走によってファンの話題を集めた。"
"第26回高松宮杯出走後に発症した屈腱炎が原因となって1996年10月に競走馬を引退した。"
"競走馬を引退したあとは種牡馬となったが、1998年9月に胃破裂を発症し、安楽死の措置がとられた。")
re.split(r'([^! ? 。、]*[!?。、]{1,3})', text)
That splits the punctuations correctly but also split on the space, outputs:
['',
'1993年8月にデビュー。',
'',
'同年11月から1995年3月にかけてクラシック三冠を含むGI5連勝、',
'',
'10連続連対を達成し、',
'1993年JRA賞最優秀3歳牡馬[† ',
'3]、',
'1994年JRA賞年度代表馬および最優秀4歳牡馬[† ',
'3]に選出された。',
'',
'1995年春に故障(股関節炎)を発症したあとはその後遺症から低迷し、',
'6戦して重賞を1勝するにとどまった(GI ',
'は5戦して未勝利)が、',
'',
'第44回阪神大賞典におけるマヤノトップガンとのマッチレースや短距離戦である第26回高松宮杯への出走によってファンの話題を集めた。',
'',
'第26回高松宮杯出走後に発症した屈腱炎が原因となって1996年10月に競走馬を引退した。',
'',
'競走馬を引退したあとは種牡馬となったが、',
'',
'1998年9月に胃破裂を発症し、',
'',
'安楽死の措置がとられた。',
'']
These segments were broken wrongly because space wasn't included in the allowed characters of the first optional group:
'1993年JRA賞最優秀3歳牡馬[† 3]、',
'1994年JRA賞年度代表馬および最優秀4歳牡馬[† 3]に選出された。',
...,
'6戦して重賞を1勝するにとどまった(GI は5戦して未勝利)が、'
How to allow characters and whitespaces in an exception in regex?
Your desired output shows a split before a parenthesis that wasn't in your regular expression attempt. Assuming that is an error, this works:
#coding:utf8
import re
text = '''1993年8月にデビュー。。。同年11月から1995年3月にかけてクラシック三冠を含むGI5連勝、10連続連対を達成し、1993年JRA賞最優秀3歳牡馬[† 3]、1994年JRA賞年度代表馬および最優秀4歳牡馬[† 3]に選出された。1995年春に故障(股関節炎)を発症したあとはその後遺症から低迷し、6戦して重賞を1勝するにとどまった(GI は5戦して未勝利)が、第44回阪神大賞典におけるマヤノトップガンとのマッチレースや短距離戦である第26回高松宮杯への出走によってファンの話題を集めた。第26回高松宮杯出走後に発症した屈腱炎が原因となって1996年10月に競走馬を引退した。競走馬を引退したあとは種牡馬となったが、1998年9月に胃破裂を発症し、安楽死の措置がとられた。'''
desired = ["1993年8月にデビュー。",
"同年11月から1995年3月にかけてクラシック三冠を含むGI5連勝、",
"10連続連対を達成し、",
"1993年JRA賞最優秀3歳牡馬[† 3]、",
"1994年JRA賞年度代表馬および最優秀4歳牡馬[† 3]に選出された。",
"1995年春に故障(股関節炎)を発症したあとはその後遺症から低迷し、",
"6戦して重賞を1勝するにとどまった(GI は5戦して未勝利)が、",
"第44回阪神大賞典におけるマヤノトップガンとのマッチレースや短距離戦である第26回高松宮杯への出走によってファンの話題を集めた。",
"第26回高松宮杯出走後に発症した屈腱炎が原因となって1996年10月に競走馬を引退した。",
"競走馬を引退したあとは種牡馬となったが、",
"1998年9月に胃破裂を発症し、",
"安楽死の措置がとられた。"]
actual = re.findall(r'([^!?。、]*[!?。、])[!?。、]*', text)
print(desired == actual)
Output:
True

Split string with multiple separators from an array (Python)

Given an array of separators:
columns = ["Name:", "ID:", "Date:", "Building:", "Room:", "Notes:"]
and a string where some columns were left blank (and there is random white space):
input = "Name: JohnID:123:45Date: 8/2/17Building:Room:Notes: i love notes"
How can I get this:
["John", "123:45", "8/2/17", "", "", "i love notes"]
I've tried simply removing the substrings to see where I can go from there but I'm still stuck
import re
input = re.sub(r'|'.join(map(re.escape, columns)), "", input)
use the list to generate a regular expression by inserting (.*) in between, then use strip to remove spaces:
import re
columns = ["Name:", "ID:", "Date:", "Building:", "Room:", "Notes:"]
s = "Name: JohnID:123:45Date: 8/2/17Building:Room:Notes: i love notes"
result = [x.strip() for x in re.match("".join(map("{}(.*)".format,columns)),s).groups()]
print(result)
yields:
['John', '123:45', '8/2/17', '', '', 'i love notes']
the strip part can be handled by the regular expression at the expense of a more complex regex, but simpler overall expression:
result = re.match("".join(map("{}\s*(.*)\s*".format,columns)),s).groups()
more complex: if field data contains regex special chars, we have to escape them (not the case here):
result = re.match("".join(["{}\s*(.*)\s*".format(re.escape(x)) for x in columns]),s).groups()
How about using re.split?
>>> import re
>>> columns = ["Name:", "ID:", "Date:", "Building:", "Room:", "Notes:"]
>>> i = "Name: JohnID:123:45Date: 8/2/17Building:Room:Notes: i love notes"
>>> re.split('|'.join(map(re.escape, columns)), i)
['', ' John', '123:45', ' 8/2/17', '', '', ' i love notes']
To get rid of the whitespace, split on whitespace too:
>>> re.split(r'\s*' + (r'\s*|\s*'.join(map(re.escape, columns))) + r'\s*', i.strip())
['', 'John', '123:45', '8/2/17', '', '', ' i love notes']

match single keyword from re.compile which has a list of keyword

i have keywords like
cat="AUTHORISATION,FORTHCOMING BOARD MEETINGS,PREVIOUS BOARD MEETINGS,BOARD MEETINGS,BOARD MEETING,MINUTES,BOARD PAPERS,AGENDA,COMMUNITY PROFILES,FORTHCOMING GOVERNOR MEETINGS,PREVIOUS GOVERNOR MEETINGS,GOVERNOR MEETINGS,GOVERNOR MEETING,GOVERNOR,COUNCIL OF GOVERNORS,GOVERNING BODY MEETINGS,COMPARISON,APC SUMMARY OF DECISIONS"
i have some pre-processing like this
cat_list=cat.split(',')
cat_list=filter(None, cat_list)
cat_list=[s.strip() for s in cat_list]
cat_list=[re.sub('\r\n' , ' ', s) for s in cat_list]
cat_list=[re.sub(r'([^\s])\s([^\s])', r'\1+(.)+\2',x) for x in cat_list]
cat_list=[re.sub(r'([a-z][a-z]+)', r'(\1)',a,flags=re.I) for a in cat_list]
regexes_cat=[re.compile((r'(?:%s)' % '|'.join(cat_list)),re.IGNORECASE),]
which gives re.compile expressions in list for me to perform re.search
so the final regex pattern after processing looks like this
(?:(AUTHORISATION)|(FORTHCOMING)+(.)+(BOARD)+(.)+(MEETINGS)|(PREVIOUS)+(.)+(BOARD)+(.)+(MEETINGS)|(BOARD)+(.)+(MEETINGS)|(BOARD)+(.)+(MEETING)|(MINUTES)|(BOARD)+(.)+(PAPERS)|(AGENDA)|(COMMUNITY)+(.)+(PROFILES)|(FORTHCOMING)+(.)+(GOVERNOR)+(.)+(MEETINGS)|(PREVIOUS)+(.)+(GOVERNOR)+(.)+(MEETINGS)|(GOVERNOR)+(.)+(MEETINGS)|(GOVERNOR)+(.)+(MEETING)|(GOVERNOR)|(COUNCIL)+(.)+(OF)+(.)+(GOVERNORS)|(GOVERNING)+(.)+(BODY)+(.)+(MEETINGS)|(COMPARISON)|(APC)+(.)+(SUMMARY)+(.)+(OF)+(.)+(DECISIONS))
but i got results like this if i print group(0)
GOVERNORS-MEETINGS.ASP?P=GOVERNORS%27.COUNCIL.MEETINGS
so i searched and found that i have to use ? to make it non-greedy but i am unable get the required output
which should be
GOVERNORS-MEETINGS
i am performing re.search against URL and text present on webpage
http://www.qehkl.nhs.uk/governors-meetings.asp?p=governors%27.council.meetings&s=main&ss=becoming.a.foundation.trust
The solution I suggest is based on the following assumptions:
The regex match should happen in the last subpart of the path (i.e. in the file part, before any eventual query string)
The query string is optional
So, the solution is to parse the URL first with urlparse to only get the string to run the regex on, and forget about lookarounds. Instead of (.)+, just use a lazy (.*?) to match any 0+ chars as few as possible:
import re
from urlparse import urlparse
cat="AUTHORISATION,FORTHCOMING BOARD MEETINGS,PREVIOUS BOARD MEETINGS,BOARD MEETINGS,BOARD MEETING,MINUTES,BOARD PAPERS,AGENDA,COMMUNITY PROFILES,FORTHCOMING GOVERNOR MEETINGS,PREVIOUS GOVERNOR MEETINGS,GOVERNOR MEETINGS,GOVERNOR MEETING,GOVERNOR,COUNCIL OF GOVERNORS,GOVERNING BODY MEETINGS,COMPARISON,APC SUMMARY OF DECISIONS"
cat_list=cat.split(',')
cat_list=filter(None, cat_list)
cat_list=[s.strip() for s in cat_list]
cat_list=[re.sub('\r\n' , ' ', s) for s in cat_list]
cat_list=[re.sub(r'([^\s])\s([^\s])', r'\1(.*?)\2',x) for x in cat_list] # Allow anything in between the keywords, but as few as possible
cat_list=[re.sub(r'([a-z][a-z]+)', r'(\1)', a, flags=re.I) for a in cat_list]
regex_cat=re.compile(r"(?:{})".format('|'.join(cat_list)),re.IGNORECASE)
#print(regex_cat.pattern)
urls = "GOVERNORS/GOVERNORS-MEETINGS.ASP?P=GOVERNORS%27.COUNCIL.MEETINGS "
o = urlparse(urls) # Parse the URL
last_subpart = o.path.split('/').pop() # Get the last subpart
m = regex_cat.search(last_subpart) # Run the regex search
if m: # If there is a match...
print(m.group()) # Print or do anything with the value
See the Python demo
Try the following code -
cat_list=cat.split(',')
cat_list=filter(None, cat_list)
cat_list=[s.strip() for s in cat_list]
cat_list=[re.sub('\r\n' , ' ', s) for s in cat_list]
#Till now all same, following statements have changes
cat_list=[re.sub(r'([^\s])\s([^\s])', r'\1+.+?\2',x) for x in cat_list]
cat_list=['(%s)'%re.sub(r'([a-z]+)', r'(\1)',a,flags=re.I) for a in cat_list]
regexes_cat=[re.compile((r'(?:%s)' % '|'.join(cat_list)),re.IGNORECASE),]
Here's the working demo.

Categories

Resources