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

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

Related

Python Regex - Get strings before and after substring

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

Using regex on Python to find any numerical value in an expression

I am trying to get all numerical value (integers,decimal,float,scientific notation) from an expression and want to differentiate them from digits that are not realy number but part of a name. For example in the expression below.
230FIC000.PV>=-2e3 211FIC00.PV <= 20 100fic>-20.4 tic200 >=45 tic100 <-2E-4 fic123 >1
the first 230 is not a numerical value as it is part of a tag (230FIC100.PV).
Using the web tool regexp.com I come up with the following expression that works for the expression above.
(?!\s)(?<!\w)[+-]?((\d+\.\d*)|(\.\d+)|(\d+))([eE][+-]?\d+)?(\s)|(?<!\w)[0-9]\d+(?<!\s)$
However when I try to use the above expression in python re.findall() I receive as result a list with 5 tuples with 6 elements on each.
import re
pat = r'(?!\s)(?<!\w)[+-]?((\d+\.\d*)|(\.\d+)|(\d+))([eE][+-]?\d+)?(\s)|(?<!\w)[0-9]\d+(?<!\s)$'
exp = '230FIC000.PV>=-2e3 211FIC00.PV <= 20 100fic>-20.4 tic200 >=45 tic100 <-2E-4 fic123 >1 '
matches = re.findall(pat,exp)
The result is
special variables
function variables
0:('2', '', '', '2', 'e3', ' ')
1:('20', '', '', '20', '', ' ')
2:('20.4', '20.4', '', '', '', ' ')
3:('45', '', '', '45', '', ' ')
4:('2', '', '', '2', 'e4', ' ')
len():5
I would like some help to undestand what is happening and if there is any way to get this done in a similar way that happen on the regexp.com.
This should take care of it. (All the items are strings)
import re
st = '230FIC000.PV>=-2e3 211FIC00.PV <= 20 100fic>-20.4 tic200 >=45 tic100 <-2E-4 fic123 >1'
re.findall(r'-?[0-9]+\.?[0-9]*(?:[Ee]\ *-?\ *[0-9]+)|-?\d+\.\d+|\b\d+\b', st)
referred: How to extract numbers from strings,
Extracting scientific numbers from string,
and Extracting decimal values from string

Python3 regex findall

Here is my issue. Given below list:
a = ['COP' , '\t\t\t', 'Basis', 'Notl', 'dv01', '6m', '9m', '1y',
'18m', '2y', '3y', "15.6", 'mm', '4.6', '4y', '5y', '10', 'mm',
'4.6', '6y', '7y', '8y', '9y', '10y', '20y', 'TOTAL', '\t\t9.2' ]
I'm trying to get some outputs like this one. The most important note is the rows
After the first number ended on "y" or "m" will come a number only if it is there in the list
Example : ('3y', '15.6', '')
SAMPLE OUTPUT ( forget about the structure that is a tuple, jsut want teh values)
('6m', '', '')
('9m', '', '')
('1y', '', '')
('18m', '', '')
('2y', '', '')
('3y', '15.6', '')
('4y', '', '')
('5y', '10', '')
('6y', '', '')
('7y', '', '')
('8y', '', '')
('9y', '', '')
('10y', '', '')
('20y', '', '')
I used the following regex that should have returned :
all numbers followed by "y" or "m" => (\b\d+[ym]\b)
and then any number (integer or not) if it appears (meaning zero or more times)=>
(\b[0-9]+.[0-9]\b)
Here is what I did, using Python3 regex and re.findall(), but still got no result
rule2 = re.compile(r"(\b\d+[ym]\b)(\b[0-9]+.*[0-9]*\b)+")
a_str = " ".join(a)
OUT2 = re.findall(rule2, a_str)
print(OUT2)
# OUT2 >>[]
Why I'm not getting the correct result?
You cannot use word boundary twice. Since data is separated by non-letter/digits use \W+ instead.
Then, escape the dot, and make it optional, or you're not going to match 10. Don't use .* as it will match too much (regex greediness)
that yields more or less what you're looking for (note that matching strict numbers, integers or floats, is trickier than that, so this isn't perfect):
rule2 = re.compile(r"\b(\d+[ym])\W+([0-9]+\.?[0-9]*)\b")
a_str = " ".join(a)
OUT2 = re.findall(rule2, a_str)
print(OUT2)
[('3y', '15.6'), ('5y', '10')]

Preserve whitespaces when using split() and join() in python

I have a data file with columns like
BBP1 0.000000 -0.150000 2.033000 0.00 -0.150 1.77
and the individual columns are separated by a varying number of whitespaces.
My goal is to read in those lines, do some math on several rows, for example multiplying column 4 by .95, and write them out to a new file. The new file should look like the original one, except for the values that I modified.
My approach would be reading in the lines as items of a list. And then I would use split() on those rows I am interested in, which will give me a sublist with the individual column values. Then I do the modification, join() the columns together and write the lines from the list to a new text file.
The problem is that I have those varying amount of whitespaces. I don't know how to introduce them back in the same way I read them in. The only way I could think of is to count characters in the line before I split them, which would be very tedious. Does someone have a better idea to tackle this problem?
You want to use re.split() in that case, with a group:
re.split(r'(\s+)', line)
would return both the columns and the whitespace so you can rejoin the line later with the same amount of whitespace included.
Example:
>>> re.split(r'(\s+)', line)
['BBP1', ' ', '0.000000', ' ', '-0.150000', ' ', '2.033000', ' ', '0.00', ' ', '-0.150', ' ', '1.77']
You probably do want to remove the newline from the end.
Other way to do this is:
s = 'BBP1 0.000000 -0.150000 2.033000 0.00 -0.150 1.77'
s.split(' ')
>>> ['BBP1', '', '', '0.000000', '', '-0.150000', '', '', '', '2.033000', '', '0.00', '-0.150', '', '', '1.77']
If we specify space character argument in split function, it creates list without eating successive space characters. So, original numbers of space characters are restored after 'join' function.
For lines that have whitespace at the beginning and/or end, a more robust pattern is (\S+) to split at non-whitespace characters:
import re
line1 = ' 4 426.2 orange\n'
line2 = '12 82.1 apple\n'
re_S = re.compile(r'(\S+)')
items1 = re_S.split(line1)
items2 = re_S.split(line2)
print(items1) # [' ', '4', ' ', '426.2', ' ', 'orange', '\n']
print(items2) # ['', '12', ' ', '82.1', ' ', 'apple', '\n']
These two lines have the same number of items after splitting, which is handy. The first and last items are always whitespace strings. These lines can be reconstituted using a join with a zero-length string:
print(repr(''.join(items1))) # ' 4 426.2 orange\n'
print(repr(''.join(items2))) # '12 82.1 apple\n'
To contrast the example with a similar pattern (\s+) (lower-case) used in the other answer here, each line splits with different result lengths and positions of the items:
re_s = re.compile(r'(\s+)')
print(re_s.split(line1)) # ['', ' ', '4', ' ', '20.0', ' ', 'orange', '\n', '']
print(re_s.split(line2)) # ['12', ' ', '82.1', ' ', 'apple', '\n', '']
As you can see, this would be a bit more difficult to process in a consistent manner.

Split string and just get number in python?

I have a string like "GoTo: 7018 6453 12654\n" I just want get the number something like this ['7018', '6453', '12654'], I tries regular expression but I can't split string to get just number here is my code:
Sample 1:
splitter = re.compile(r'\D');
match1 = splitter.split("GoTo: 7018 6453 12654\n")
my output is: ['', '', '', '', '', '', '', '', '7018', '6453', '12654', '']
Sample 2:
splitter = re.compile(r'\W');
match1 = splitter.split("GoTo: 7018 6453 12654\n")
my output is: ['GoTo', '', '7018', '6453', '12654', '']
If all your numbers are positive integers, you can do that without regular expressions by using the isdigit() method:
>>> text = "GoTo: 7018 6453 12654\n"
>>> [token for token in text.split() if token.isdigit()]
['7018', '6453', '12654']
>>> re.findall(r'\d+', 'GoTo: 7018 6453 12654\n')
['7018', '6453', '12654']
>>> import re
>>> re.findall("[0-9]+", "GoTo: 7018 6453 12654\n")
['7018', '6453', '12654']
>>>
You can follow your current method in sample 1 along with this code:
filter (lambda a: a != '', match1)
Try this:
import re
splitter = re.compile(r'\d+')
match1 = splitter.findall("GoTo: 7018 6453 12654\n")
print match1

Categories

Resources