Find specific string sections in python - python

I want to be able to grab sections of strings with a function. Here is an example:
def get_sec(s1,s2,first='{',last='}'):
start = s2.index(first)
end = -(len(s2) - s2.index(last)) + 1
a = "".join(s2.split(first + last))
b = s1[:start] + s1[end:]
print a
print b
if a == b:
return s1[start:end]
else:
print "The strings did not match up"
string = 'contentonemore'
finder = 'content{}more'
print get_sec(string,finder)
#'one'
So that example works...my issue is I want multiple sections, not just one. So my function needs to be able to work for any amount of sections, for example:
test_str = 'contwotentonemorethree'
test_find = 'con{}tent{}more{}'
print get_sec(test_str,test_find)
#['one','two','three']
any ideas on how I can make that function work for an arbitrary number of replacements?

You probably want to use the standard python regex library
import re
a = re.search('con(.*)tent(.*)more(.*)','contwotentonemorethree')
print a.groups()
# ('two', 'one', 'three')
or
print re.findall('con(.)tent(.)more(.*)','contwotentonemorethree')
# [('two', 'one', 'three')]
edit:
you can escape special character in a string using
re.escape(str)
example:
part1 = re.escape('con(')
part2 = re.escape('(tent')
print re.findall(part1 + '(.*)' + part2,'con(two)tent')

It is not just "use regex". you are trying to actually implement regex. well, the easiest way for implemeting regex will be using the re library. of course.

ummm use regex?
import re
re.findall("con(.*)tent(.*)more(.*)",my_string)

Looks like you want something with regular expressions.
Here's python's page about regular expressions: http://docs.python.org/2/library/re.html
As an example, if say you knew that the string would only be broken into segments "con", "tent", "more" you could have:
import re
regex = re.compile(r"(con).*(tent).*(more).*")
s = 'conxxxxtentxxxxxmore'
match = regex.match(s)
Then find the indices of the matches with:
index1 = s.index(match.group(1))
index2 = s.index(match.group(2))
index3 = s.index(match.group(3))
Or if you wanted to find the locations of the other characters (.*):
regex = re.compile(r"con(.*)tent(.*)more(.*)")

Related

Elegant way of extracting substrings matching regex?

Is there a nice way in Python to do:
Check a String matches a set of regular expressions
If yes: get the matching parts back as tuples.
So essentially I want a simple way to enter simple parser/scanner grammars, and simply extract all matching in a certain structure (e.g. tuples)
So suppose we have encoded in a String a country code, an city name and an index. We want to extract this:
input = "123-NEWYORK-[2]"
grammar = "<country,[0-9]+>-<city,[A-Z]*>-[<index,[0-9]*>"
res = HOW_TO_DO_THIS(input,grammar)
if res is None:
print("Does not match")
else
(countrycode,city,index) = res
With python3 you can do, note that the regex has been modified:
import re
input = "123-NEWYORK-[2]"
grammar = r"(?P<country>[0-9]+)-(?P<city>[A-Z]*)-(?P<index>\[[0-9]*\])"
res = re.findall(grammar, input)
if not res:
print("Does not match")
else:
(countrycode,city,index) = res[0]
print(countrycode)
Modifications:
The correct regex would be (?P[0-9]+)-(?P[A-Z])-(?P[[0-9]])
The syntax for regex module in python is re.findall(patter, input_string). Not the opposite.
if not x is easier (and more generic) than if x is None
Check out this code. This is just for simple text lookup but you can extend according to your scenario
import re
f=open('sample.txt',"w")
f.write("<p class = m>babygameover</p>")
f.close()
f=open('sample.txt','r')
string = "<p class = m>(.+?)</p>" # regular expression
pattern = re.compile(string) # compiling
text = f.read()
search = re.findall(pattern,text) # searching
print search

Extract substrings from logical expressions

Let's say I have a string that looks like this:
myStr = '(Txt_l1 (Txt_l2)) or (Txt2_l1 (Txt2_l2))'
What I would like to obtain in the end would be:
myStr_l1 = '(Txt_l1) or (Txt2_l1)'
and
myStr_l2 = '(Txt_l2) or (Txt2_l2)'
Some properties:
all "Txt_"-elements of the string start with an uppercase letter
the string can contain much more elements (so there could also be Txt3, Txt4,...)
the suffixes '_l1' and '_l2' look different in reality; they cannot be used for matching (I chose them for demonstration purposes)
I found a way to get the first part done by using:
myStr_l1 = re.sub('\(\w+\)','',myStr)
which gives me
'(Txt_l1 ) or (Txt2_l1 )'
However, I don't know how to obtain myStr_l2. My idea was to remove everything between two open parentheses. But when I do something like this:
re.sub('\(w+\(', '', myStr)
the entire string is returned.
re.sub('\(.*\(', '', myStr)
removes - of course - far too much and gives me
'Txt2_l2))'
Does anyone have an idea how to get myStr_l2?
When there is an "and" instead of an "or", the strings look slightly different:
myStr2 = '(Txt_l1 (Txt_l2) and Txt2_l1 (Txt2_l2))'
Then I can still use the command from above:
re.sub('\(\w+\)','',myStr2)
which gives:
'(Txt_l1 and Txt2_l1 )'
but I again fail to get myStr2_l2. How would I do this for these kind of strings?
And how would one then do this for mixed expressions with "and" and "or" e.g. like this:
myStr3 = '(Txt_l1 (Txt_l2) and Txt2_l1 (Txt2_l2)) or (Txt3_l1 (Txt3_l2) and Txt4_l1 (Txt2_l2))'
re.sub('\(\w+\)','',myStr3)
gives me
'(Txt_l1 and Txt2_l1 ) or (Txt3_l1 and Txt4_l1 )'
but again: How would I obtain myStr3_l2?
Regexp is not powerful enough for nested expressions (in your case: nested elements in parentheses). You will have to write a parser. Look at https://pyparsing.wikispaces.com/
I'm not entirely sure what you want but I wrote this to strip everything between the parenthesis.
import re
mystr = '(Txt_l1 (Txt_l2)) or (Txt2_l1 (Txt2_l2))'
sets = mystr.split(' or ')
noParens = []
for line in sets:
mat = re.match(r'\((.* )\((.*\)\))', line, re.M)
if mat:
noParens.append(mat.group(1))
noParens.append(mat.group(2).replace(')',''))
print(noParens)
This takes all the parenthesis away and puts your elements in a list. Here's an alternate way of doing it without using Regular Expressions.
mystr = '(Txt_l1 (Txt_l2)) or (Txt2_l1 (Txt2_l2))'
noParens = []
mystr = mystr.replace(' or ', ' ')
mystr = mystr.replace(')','')
mystr = mystr.replace('(','')
noParens = mystr.split()
print(noParens)

Python splitting string to find specific content

I am trying to split a string in python to extract a particular part. I am able to get the part of the string before the symbol < but how do i get the bit after? e.g. the emailaddress part?
>>> s = 'texttexttextblahblah <emailaddress>'
>>> s = s[:s.find('<')]
>>> print s
This above code gives the output texttexttextblahblah 
s = s[s.find('<')+1:-1]
or
s = s.split('<')[1][:-1]
cha0site's and ig0774's answers are pretty straightforward for this case, but it would probably help you to learn regular expressions for times when it's not so simple.
import re
fullString = 'texttexttextblahblah <emailaddress>'
m = re.match(r'(\S+) <(\S+)>', fullString)
part1 = m.group(1)
part2 = m.group(2)
Perhaps being a bit more explicit with a regex isn't a bad idea in this case:
import re
match = re.search("""
(?<=<) # Make sure the match starts after a <
[^<>]* # Match any number of characters except angle brackets""",
subject, re.VERBOSE)
if match:
result = match.group()

regex in python 2.4

I have a string in python as below:
"\\B1\\B1xxA1xxMdl1zzInoAEROzzMofIN"
I want to get the string as
"B1xxA1xxMdl1zzInoAEROzzMofIN"
I think this can be done using regex but could not achieve it yet. Please give me an idea.
st = "\B1\B1xxA1xxMdl1zzInoAEROzzMofIN"
s = re.sub(r"\\","",st)
idx = s.rindex("B1")
print s[idx:]
output = 'B1xxA1xxMdl1zzInoAEROzzMofIN'
OR
st = "\B1\B1xxA1xxMdl1zzInoAEROzzMofIN"
idx = st.rindex("\\")
print st[idx+1:]
output = 'B1xxA1xxMdl1zzInoAEROzzMofIN'
Here is a try:
import re
s = "\\B1\\B1xxA1xxMdl1zzInoAEROzzMofIN"
s = re.sub(r"\\[^\\]+\\","", s)
print s
Tested on http://py-ide-online.appspot.com (couldn't find a way to share though)
[EDIT] For some explanation, have a look at the Python regex documentation page and the first comment of this SO question:
How to remove symbols from a string with Python?
because using brackets [] can be tricky (IMHO)
In this case, [^\\] means anything but two backslashes \\.
So [^\\]+ means one or more character that matches anything but two backslashes \\.
If the desired section of the string is always on the RHS of a \ char then you could use:
string = "\\B1\\B1xxA1xxMdl1zzInoAEROzzMofIN"
string.rpartition("\\")[2]
output = 'B1xxA1xxMdl1zzInoAEROzzMofIN'

python regex for repeating string

I am wanting to verify and then parse this string (in quotes):
string = "start: c12354, c3456, 34526; other stuff that I don't care about"
//Note that some codes begin with 'c'
I would like to verify that the string starts with 'start:' and ends with ';'
Afterward, I would like to have a regex parse out the strings. I tried the following python re code:
regx = r"start: (c?[0-9]+,?)+;"
reg = re.compile(regx)
matched = reg.search(string)
print ' matched.groups()', matched.groups()
I have tried different variations but I can either get the first or the last code but not a list of all three.
Or should I abandon using a regex?
EDIT: updated to reflect part of the problem space I neglected and fixed string difference.
Thanks for all the suggestions - in such a short time.
In Python, this isn’t possible with a single regular expression: each capture of a group overrides the last capture of that same group (in .NET, this would actually be possible since the engine distinguishes between captures and groups).
Your easiest solution is to first extract the part between start: and ; and then using a regular expression to return all matches, not just a single match, using re.findall('c?[0-9]+', text).
You could use the standard string tools, which are pretty much always more readable.
s = "start: c12354, c3456, 34526;"
s.startswith("start:") # returns a boolean if it starts with this string
s.endswith(";") # returns a boolean if it ends with this string
s[6:-1].split(', ') # will give you a list of tokens separated by the string ", "
This can be done (pretty elegantly) with a tool like Pyparsing:
from pyparsing import Group, Literal, Optional, Word
import string
code = Group(Optional(Literal("c"), default='') + Word(string.digits) + Optional(Literal(","), default=''))
parser = Literal("start:") + OneOrMore(code) + Literal(";")
# Read lines from file:
with open('lines.txt', 'r') as f:
for line in f:
try:
result = parser.parseString(line)
codes = [c[1] for c in result[1:-1]]
# Do something with teh codez...
except ParseException exc:
# Oh noes: string doesn't match!
continue
Cleaner than a regular expression, returns a list of codes (no need to string.split), and ignores any extra characters in the line, just like your example.
import re
sstr = re.compile(r'start:([^;]*);')
slst = re.compile(r'(?:c?)(\d+)')
mystr = "start: c12354, c3456, 34526; other stuff that I don't care about"
match = re.match(sstr, mystr)
if match:
res = re.findall(slst, match.group(0))
results in
['12354', '3456', '34526']

Categories