Python : splitting string with multiple characters - python

I have a following input :
"auth-server $na me$ $1n ame$ [position [$pr io$]] xxxx [match-fqdn [[$fq dn$] [all]]]"
I need to store them in a list with $, <, and > serving as delimiters.
Expected output:
['auth-server', '$na me$', '$1n ame$', '[position', '[$pr io$]]', 'xxxx', '[match-fqdn', '[[$fq dn$]', '[all]]]']
How can I do this?

What you could do is split it on the spaces, then go through each substring and check if it starts with one of the special delimiters. If it does, start a new string and append subsequent strings until you get to the end delimiter. Then remove those substrings and replace them with the new one.

I think what you want is
import re
re.split(r"(?<=\]) | (?=\$|\[)", "auth-server $na me$ $1n ame$ [position [$pr io$]] xxxx [match-fqdn [[$fq dn$] [all]]]")
This yields
['auth-server', '$na me$', '$1n ame$', '[position', '[$pr io$]]', 'xxxx', '[match-fqdn', '[[$fq dn$]', '[all]]]']
Note however that this is not exactly what you described, but what matches your example. It seems that you want to split on spaces when they are preceded by ] or followed by $ or [.

try re.split and a regex who make someone cry blood
import re
print re.split(r'(\$[^\$]+\$|\[\S+([^\]]+\]\])?|[-0-9a-zA-Z]+)',"auth-server $na me$ $1n ame$ [position [$pr io$]] xxxx [match-fqdn [[$fq dn$] [all]]]")

consider using pyparsing:
from pyparsing import *
enclosed = Forward()
nestedBrackets = nestedExpr('[', ']')
enclosed << ( Combine(Group(Optional('$') + Word(alphas) + Optional('$'))) | nestedBrackets )
print enclosed.parseString(data).asList()
output:
[['auth-server', '$na', 'me$', '$1n', 'ame$', ['position', ['$pr', 'io$']], 'xxxx',
['match-fqdn', [['$fq', 'dn$'], ['all']]]]]

Not quite a full answer, but I used regexp search...
a = "auth-server $na me$ $1n ame$ [position [$pr io$]] xxxx [match-fqdn [[$fq dn$] [all]]]"
m = re.search('\$.*\$', a)
combine this with a.split() and we can do the math...

Related

How to extract value from re?

import re
cc = 'test 5555555555555555/03/22/284 test'
cc = re.findall('[0-9]{15,16}\/[0-9]{2,4}\/[0-9]{2,4}\/[0-9]{3,4}', cc)
print(cc)
[5555555555555555/03/22/284]
This code is working fine but if i put 5555555555555555|03|22|284 on cc variable then this output will come:
[]
I want one condition if it contains '|' then it gives output: 5555555555555555|03|22|284 or '/' then also it will give output: 5555555555555555/03/22/284
Just replace all the /s in your regex (which incidentally don't need to be backslashed) with [/|], which matches either a / or a |. Or if you want backslashes, too, as in your comment on Zain's answer, [/|\\]. (You should always use raw strings r'...' for regexes since they have their own interpretation of backslashes; in a regular string, [/|\\] would have to be written [/|\\\\].)
match = re.findall(
r'[0-9]{15,16}[/|\\][0-9]{2,4}[/|\\][0-9]{2,4}[/|\\][0-9]{3,4}',
cc)
Any other characters you want to include, like colons, can likewise be added between the square brackets.
If you want to accept repeated characters – and treat them as a single delimiter – you can add + to accept "1 or more" of any of the characters:
match = re.findall(
r'[0-9]{15,16}[:/|\\]+[0-9]{2,4}[:/|\\]+[0-9]{2,4}[:/|\\]+[0-9]{3,4}',
cc)
But that will accept, for example, 555555555555555:/|\\03::|::22\\//284 as valid. If you want to be pickier you can replace the character class with a set of alternates, which can be any length. Just separate the options via | – note that outside of the square brackets, a literal | needs a backslash – and put (?:...) around the whole thing: (?:/|\\|\||:|...) whatever, in place of the square-bracketed expressions up there.
I don't recommend assigning the result of the findall back to the original cc variable; for one thing, it's a list, not a string. (You can get the string with e.g. new_cc = match[0]).
Better to create a new variable so (1) you still have the original value in case you need it and (2) when you use the new value in later code, it's clear that it's different.
In fact, if you're going to the trouble of matching this pattern, you might as well go ahead and extract all the components of it at the same time. Just put (...) around the bits you want to keep, and they'll be put in a tuple as the result of that match:
import re
pat = re.compile(r'([0-9]{15,16})[:/|\\]+([0-9]{2,4})[:/|\\]+([0-9]{2,4})[:/|\\]+([0-9]{3,4})')
cc = 'test 5555555555555555/03/22/284 test'
match, = pat.findall(cc)
print(match)
Which outputs this:
('5555555555555555', '03', '22', '284')
Define both options in re to let your string work with both e.g. the following RE used checks for both "\" and also "|" in the string
import re
cc = 'test 5555555555555555/03/22/284 test'
#cc = 'test 5555555555555555|03|22|284 test'
cc = re.findall('[0-9]{15,16}[\/|][0-9]{2,4}[\/|][0-9]{2,4}[\/|][0-9]{3,4}', cc)
print(cc)

Delete specific duplicated punctuation from string

I have this string s = "(0|\\+33)[1-9]( *[0-9]{2}){4}". And I want to delete just the duplicated just one ' \ ', like I want the rsult to look like (0|\+33)[1-9]( *[0-9]{2}){4}.
When I used this code, all the duplicated characters are removed:
result = "".join(dict.fromkeys(s)).
But in my case I want just to remove the duplicated ' \ '. Any help is highly appreciated
A solution using the re module:
import re
s = r"(0|\\+33)[1-9]( *[0-9]{2}){4}"
s = re.sub(r"\\(?=\\)", "", s)
print(s)
I look for all backslashes, that are followed by another backslash and replace it with an empty sign.
Output: (0|\+33)[1-9]( *[0-9]{2}){4}​
The function you need is replace
s = "(0|\\+33)[1-9]( *[0-9]{2}){4}"
result = s.replace("\\","")
EDIT
I see now that you want to remove just one \ and not both.
In order to do this you have to modify the call to replace this way
result = s.replace("\","",1) # last argument is the number of occurrances to replace
or
result = s.replace("\\","\")
EDIT of the EDIT
Backslashes are special in Python.
I'm using Python 3.10.5. If I do
x = "ab\c"
y = "ab\\c"
print(len(x)==len(y))
I get a True.
That's because backslashes are used to escape special characters, and that makes the backslash a special character :)
I suggest you to try a little bit with replace until you get what you need.

replacing special characters in string Python

I'm trying to replace special characters in a data frame with unaccented or different ones.
I can replace one with
df['col_name'] = df.col_name.str.replace('?','j')
this turned the '?' to 'j' - but - I can't seem to figure out how to change more than one..
I have a list of special characters that I want to change. I've tried using a dictionary but it doesn't seem to work
the_reps = {'?','j'}
df1 = df.replace(the_reps, regex = True)
this gave me the error nothing to replace at position 0
EDIT:
this is what worked - although it is probably not that pretty:
df[col]=df.col.str.replace('old char','new char')
df[col]=df.col.str.replace('old char','new char')
df[col]=df.col.str.replace('old char','new char')
df[col]=df.col.str.replace('old char','new char')...
for each one ..
import re
s=re.sub("[_list of special characters_]","",_your string goes here_)
print(s)
An example for this..
str="Hello$#& Python3$"
import re
s=re.sub("[$#&]","",str)
print (s)
#Output:Hello Python3
Explanation goes here..
s=re.sub("[$#&]","",s)
Pattern to be replaced → “[$#&]”
[] used to indicate a set of characters
[$#&] → will match either $ or # or &
The replacement string is given as an empty string
If these characters are found in the string, they’ll be replaced with an empty string
you can use Series.replace with a dictionary
#d = { 'actual character ':'replacement ',...}
df.columns = df.columns.to_series().replace(d, regex=True)
Try This:
import re
my_str = "hello Fayzan-Bhatti Ho~!w"
my_new_string = re.sub('[^a-zA-Z0-9 \n\.]', '', my_str)
print my_new_string
Output: hello FayzanBhatti How

Remove variable parts of a string that start and end the same

I have a string as the following:
'1:CH,AG,ME,GS,AP,CH,HE,AC,AC,AG,CA,HE,AT,AT,AC,AT,OG,NE,AG,AC,CS,OD\n&:TA,EB,PA,AC,BR,TH,PO,AC,2I,AC,TH,PE,TH,AZ,AZ,ZE,CS,OD,CH,EO,ZE,OG\n&:TH,ZE,ZE,HE,HE,HP,HP,OG,HP,ZE\n2:ZE,FD,FD,AG,EO,OG,AG,NE,RU,GS,HP,ZE,ZE,HM,HM,PC,PC,AS,AS,TY,TY,AG\n&:AG,GS,NO,EU,ZF,HE,AT,AT,OD,OD,EB,OD,GS,TR,OD,AC,TR,GS,OD,TR,OD,AT,GS\n&:CA,GS,NE,GS,AG,PS,HL,AG,NE,ID,AJ,AX,DI,OD,ME,AT,GS,MU,HO,PB,LT,9Z,PT,9Y\n&:9W,9X,AR,9V,9U,9T,AX,9S,9R,AT,AJ,DI,ST,EA,AG,ME,NE,MU,9Q,9P,9O,9N,9M,9L\n&:9K,ID,MG,OD,FY,AU,AU,HR,HR,9J,TL,9I,9H,9G,9F,AC,BR,AC,9E,9D,9C,9B,99\n'
As you can see, I would like to get the '\n(number or & here):' replaced by ','
Since they all start with '\n' and end with ':' I believe that there should be a way to replace them all at once.
The output would be as the sort:
'CH,AG,ME,GS,AP,CH,HE,AC,AC,AG,CA,HE,AT,AT,AC,AT,OG,NE,AG,AC,CS,OD,TA,EB,PA,AC,BR,TH,PO,AC,2I,AC,TH,PE,TH,AZ,AZ,ZE,CS,OD,CH,EO,ZE,OG,TH,ZE,ZE,HE,HE,HP,HP,OG,HP,ZE,ZE,FD,FD,AG,EO,OG,AG,NE,RU,GS,HP,ZE,ZE,HM,HM,PC,PC,AS,AS,TY,TY,AG,AG,GS,NO,EU,ZF,HE,AT,AT,OD,OD,EB,OD,GS,TR,OD,AC,TR,GS,OD,TR,OD,AT,GS,CA,GS,NE,GS,AG,PS,HL,AG,NE,ID,AJ,AX,DI,OD,ME,AT,GS,MU,HO,PB,LT,9Z,PT,9Y,9W,9X,AR,9V,9U,9T,AX,9S,9R,AT,AJ,DI,ST,EA,AG,ME,NE,MU,9Q,9P,9O,9N,9M,9L,9K,ID,MG,OD,FY,AU,AU,HR,HR,9J,TL,9I,9H,9G,9F,AC,BR,AC,9E,9D,9C,9B,99'
What could work was making a for lop for numbers and &.
string.replace('\n&:',',')
for i in range(1,20):
string.replace('\ni:',',')
But I believe there must be a better way.
You can use regex to get the job done:
Input:
import re
text = '1:CH,AG,ME,GS,AP,CH,HE,AC,AC,AG,CA,HE,AT,AT,AC,AT,OG,NE,AG,AC,CS,OD\n&:TA,EB,PA,AC,BR,TH,PO,AC,2I,AC,TH,PE,TH,AZ,AZ,ZE,CS,OD,CH,EO,ZE,OG\n&:TH,ZE,ZE,HE,HE,HP,HP,OG,HP,ZE\n2:ZE,FD,FD,AG,EO,OG,AG,NE,RU,GS,HP,ZE,ZE,HM,HM,PC,PC,AS,AS,TY,TY,AG\n&:AG,GS,NO,EU,ZF,HE,AT,AT,OD,OD,EB,OD,GS,TR,OD,AC,TR,GS,OD,TR,OD,AT,GS\n&:CA,GS,NE,GS,AG,PS,HL,AG,NE,ID,AJ,AX,DI,OD,ME,AT,GS,MU,HO,PB,LT,9Z,PT,9Y\n&:9W,9X,AR,9V,9U,9T,AX,9S,9R,AT,AJ,DI,ST,EA,AG,ME,NE,MU,9Q,9P,9O,9N,9M,9L\n&:9K,ID,MG,OD,FY,AU,AU,HR,HR,9J,TL,9I,9H,9G,9F,AC,BR,AC,9E,9D,9C,9B,99\n'
text = re.sub(r'\n&*(\d*:)*',',', text[2:]).rstrip(',')
Output:
'CH,AG,ME,GS,AP,CH,HE,AC,AC,AG,CA,HE,AT,AT,AC,AT,OG,NE,AG,AC,CS,OD,TA,EB,PA,AC,BR,TH,PO,AC,2I,AC,TH,PE,TH,AZ,AZ,ZE,CS,OD,CH,EO,ZE,OG,TH,ZE,ZE,HE,HE,HP,HP,OG,HP,ZE,ZE,FD,FD,AG,EO,OG,AG,NE,RU,GS,HP,ZE,ZE,HM,HM,PC,PC,AS,AS,TY,TY,AG,AG,GS,NO,EU,ZF,HE,AT,AT,OD,OD,EB,OD,GS,TR,OD,AC,TR,GS,OD,TR,OD,AT,GS,CA,GS,NE,GS,AG,PS,HL,AG,NE,ID,AJ,AX,DI,OD,ME,AT,GS,MU,HO,PB,LT,9Z,PT,9Y,9W,9X,AR,9V,9U,9T,AX,9S,9R,AT,AJ,DI,ST,EA,AG,ME,NE,MU,9Q,9P,9O,9N,9M,9L,9K,ID,MG,OD,FY,AU,AU,HR,HR,9J,TL,9I,9H,9G,9F,AC,BR,AC,9E,9D,9C,9B,99'
You can use a regular expression replace:
s = '1:CH,AG,ME,GS,AP,CH,HE,AC,AC,AG,CA,HE,AT,AT,AC,AT,OG,NE,AG,AC,CS,OD\n&:TA,EB,PA,AC,BR,TH,PO,AC,2I,AC,TH,PE,TH,AZ,AZ,ZE,CS,OD,CH,EO,ZE,OG\n&:TH,ZE,ZE,HE,HE,HP,HP,OG,HP,ZE\n2:ZE,FD,FD,AG,EO,OG,AG,NE,RU,GS,HP,ZE,ZE,HM,HM,PC,PC,AS,AS,TY,TY,AG\n&:AG,GS,NO,EU,ZF,HE,AT,AT,OD,OD,EB,OD,GS,TR,OD,AC,TR,GS,OD,TR,OD,AT,GS\n&:CA,GS,NE,GS,AG,PS,HL,AG,NE,ID,AJ,AX,DI,OD,ME,AT,GS,MU,HO,PB,LT,9Z,PT,9Y\n&:9W,9X,AR,9V,9U,9T,AX,9S,9R,AT,AJ,DI,ST,EA,AG,ME,NE,MU,9Q,9P,9O,9N,9M,9L\n&:9K,ID,MG,OD,FY,AU,AU,HR,HR,9J,TL,9I,9H,9G,9F,AC,BR,AC,9E,9D,9C,9B,99\n'
s = re.sub(r"(\n\d*?:)|(\n&:)", ",", s).strip() # replaces the middle bits with commas and strips trailing \n
s = re.sub(r"^(\d*?:)|(&:)", "", s) # removes the initial 1: or similar

regex replace '...' at the end of the string

I have a string like:
text1 = 'python...is...fun...'
I want to replace the multiple '.'s to one '.' only when they are at the end of the string, i want the output to be:
python...is...fun.
So when there is only one '.' at the end of the string, then it won't be replaced
text2 = 'python...is...fun.'
and the output is just the same as text2
My regex is like this:
text = re.sub(r'(.*)\.{2,}$', r'\1.', text)
which i want to match any string then {2 to n} of '.' at the end of the string, but the output is:
python...is...fun..
any ideas how to do this?
Thx in advance!
You are making it a bit complex, you can easily do it by using regex as \.+$ and replace the regex pattern with single . character.
>>> text1 = 'python...is...fun...'
>>> new_text = re.sub(r"\.+$", ".", text1)
>>> 'python...is...fun.'
You may extend this regex further to handle the cases with input such as ... only, etc but the main concept was that there is no need to counting the number of ., as you have done in your answer.
Just look for the string ending with three periods, and replace them with a single one.
import re
x = "foo...bar...quux..."
print(re.sub('\.{2,}$', '.', x))
// foo...bar...quux.
import re
print(re.sub(r'\.{2,}$', '.', 'I...love...python...'))
As simple as that. Note that you need to escape the . because otherwise, it means whichever char
except \n.
I want to replace the multiple '.'s to one '.' only when they are at
the end of the string
For such simple case it's easier to substitute without importing re module, checking the value of the last 3 characters:
text1 = 'python...is...fun...'
text1 = text1[:-2] if text1[-3:] == '...' else text1
print(text1)
The output:
python...is...fun.

Categories