Looking for a way to use a Python regex to extract all the characters in a string between to indexes. My code is below:
import re
txt = "Hula hoops are fun."
x = re.search(r"hoops", txt)
c = x.span()
a = c[0]
b = c[1]
print(a) # prints 5
print(b) # prints 10
txt2 = "Hula loops are fun."
z = re.???(a, b, txt2) #<------ Incorrect
print(z)
What I am trying to figure out is to somehow use a and b to get z = "loops" in txt2 (the rewrite of txt). Is there a python regex command to do this?
you can use z = txt[a:b] to extract all characters between a and b indices.
Why not using slices(the obvious way)?
z = txt2[a:b]
print(z) # loops
If you really want to use regex, you need to consume a . character a times to reach a because Regex doesn't have indexing directly. Then get the next b - a characters. In your case you end up with (?<=.{5}).{5} pattern. (?<=.{5}) part is a positive lookbehind assertion.
pat = rf"(?<=.{{{str(a)}}}).{{{str(b - a)}}}"
print(re.search(pat, txt2))
output:
<re.Match object; span=(5, 10), match='loops'>
import re
txt = "Hula hoops are fun."
x = re.search(r"hoops", txt)
c = x.span()
a = c[0]
b = c[1]
print(a) # prints 5
print(b) # prints 10
txt2 = "Hula loops are fun."
txt3 = list(txt2)
xy = txt3[a:b]
z = ""
for item in xy:
z = z + item
print(z)
Following this logic :
a,b = 0,0
I was expecting this to work :
a,b += 1,1
SyntaxError: illegal expression for augmented assignment
so here i am.
Is there anyway to achieve this in one line ?
Think of it like a list of "how to update each variable" (variables to the left, formulas to the right).
a, b = a+1, b+1
As already mentioned by others, you could combine two statements into one line as a += 1; b += 1.
But, if you prefer a single statement in the same "spirit" as a, b = 0, 0 then try this:
a, b = a + 1, b + 1
The way these assignments work is that a list of variables is assigned a list of values:
variable
value
a
0
b
0
→ a = 0; b = 0 → a, b = 0, 0
variable
value
a
a + 1
b
b + 1
→ a = a + 1; b = b + 1 → a, b = a + 1, b + 1
You can either use multiple statements, one per table row, or a single statement where all the values in the left column go on one side of the = and all the values in the right column go on the other side.
This works only for = though. Your idea a, b += 1 firstly wouldn't work for the same reason a, b = 0 doesn't (there is only one right-hand side value), but a, b += 1, 1 unfortunately also doesn't work, just because Python doesn't support this concept. + with tuples would concatenate them into a larger tuple, not add each of their elements ((1, 2) + (3, 4) is (1, 2, 3, 4) and not (4, 6)).
If you want it in 1 line here is what you can do.. a,b=0 is not the right way , it should have been a=b=0 or a,b=0,0
a=b=0
a+=1;b+=1
You can use map to apply your increment or other operation
a,b=0,0
a, b = map( lambda x : x+1, [a,b])
output
1,1
I have a bit of code that I want to run multiple times. That seams trivial but there is a twist: I want to change the code in a specific way between iterations. For example:
A = 1
B = ['+','-','/'.'*','**']
C = []
for x in range(len(B)):
C.append(A{B[x]}100)
print(C)
Now, I know this code doesn't work and it's not a proper Python syntax, but i't just an example of what I'd like the code to do.
Ideally I'd get C as a list where 0th element is 1 + 100, 1st element is 1 - 100, 2nd element is 1 / 100 etc. (N.b.: NOT '1 + 100' string. A result of 1 + 100 calculation - 101). Basically I want the code to change itself between iterations of loop in a defined way.
I do not want to define some lengthy if/elif statement since list B is very, very long.
Edit:
Let me give another example. This one is more relevant to my problem.
A = ['mom','dad','me','you','c']
B = ['a','b','something','nothing','cat']
for x in range(len(A)):
C_{A[x]} = B[x]
I want to end up with 5 new variables so that:
Print(C_mom)
a
Print(C_dad)
b
Print(C_c)
cat
Again, I recognize this is not a proper python syntax and this code doesn't work.
First create a dict where each string '+','*' etc point to it's corresponding method imported from operator module.
Now loop over B and fetch the corresponding method from the ops dict and pass the operands to the method.
>>> from operator import add,sub,mul,div,pow
>>> ops = {'+':add,'-':sub,'/':div, '*':mul,'**':pow}
>>> B = ['+','-','/','*','**']
>>> A = 1
>>> [ops[item](A,100) for item in B]
[101, -99, 0, 100, 1]
Use '/': operator.truediv if you want ops['/'](1,100) to return 0.01 instead of 0.
Update:
Creating dynamic variables in python is not a good idea, you should better use a dict here:
>>> A = [1,2,3,4,5]
>>> B = ['a','b','something','nothing','cat']
>>> c = {x:y for x,y in zip(A,B)}
>>> c[1]
'a'
>>> c[2]
'b'
>>> c[5]
'cat
Use globals() to create dynamic variables(don't use this method):
for x,y in zip(A,B):
globals()['C'+str(x)] =y
...
>>> C1
'a'
>>> C2
'b'
i know the for loop:
for i range(2, 6):
print i
gives this output:
2
3
4
5
can i also do this somehow with letters?
for example:
# an example for what i'm looking for
for i in range(c, h):
print i
c
d
f
g
I think it's nicer to add 1 to ord('g') than using ord('h')
for code in range(ord('c'), ord('g') + 1):
print chr(code)
because what if you want to go to 'z', you need to know what follows 'z' . I bet you can type + 1 faster than you can look it up.
for i in 'cdefg':
...
for i in (chr(x) for x in range(ord('c'), ord('h'))):
This also works, this way its very explicit what you are working with:
import string
s = string.ascii_lowercase
for i in s[s.index('c'):s.index('h')]:
print i
There's no reason not to use:
>>> for char in "cdefg":
... print(char)
c
d
e
f
g
Even if you weren't a programmer, you could figure out what the loop does, it's basically English.
It's also much cleaner, it's shorter, and the best part is that it's 6 times faster than the chr(ord()) solution:
>>> import timeit
>>> timeit.timeit("for i in 'abcdefg': x = i")
0.27417739599968627
>>> timeit.timeit("for i in range(ord('a'), ord('g') + 1): x = chr(i)")
1.7386019650002709
How about this?
for code in range(ord('c'), ord('h')):
print chr(code)
I want to swap each pair of characters in a string. '2143' becomes '1234', 'badcfe' becomes 'abcdef'.
How can I do this in Python?
oneliner:
>>> s = 'badcfe'
>>> ''.join([ s[x:x+2][::-1] for x in range(0, len(s), 2) ])
'abcdef'
s[x:x+2] returns string slice from x to x+2; it is safe for odd len(s).
[::-1] reverses the string in Python
range(0, len(s), 2) returns 0, 2, 4, 6 ... while x < len(s)
The usual way to swap two items in Python is:
a, b = b, a
So it would seem to me that you would just do the same with an extended slice. However, it is slightly complicated because strings aren't mutable; so you have to convert to a list and then back to a string.
Therefore, I would do the following:
>>> s = 'badcfe'
>>> t = list(s)
>>> t[::2], t[1::2] = t[1::2], t[::2]
>>> ''.join(t)
'abcdef'
Here's one way...
>>> s = '2134'
>>> def swap(c, i, j):
... c = list(c)
... c[i], c[j] = c[j], c[i]
... return ''.join(c)
...
>>> swap(s, 0, 1)
'1234'
>>>
''.join(s[i+1]+s[i] for i in range(0, len(s), 2)) # 10.6 usec per loop
or
''.join(x+y for x, y in zip(s[1::2], s[::2])) # 10.3 usec per loop
or if the string can have an odd length:
''.join(x+y for x, y in itertools.izip_longest(s[1::2], s[::2], fillvalue=''))
Note that this won't work with old versions of Python (if I'm not mistaking older than 2.5).
The benchmark was run on python-2.7-8.fc14.1.x86_64 and a Core 2 Duo 6400 CPU with s='0123456789'*4.
If performance or elegance is not an issue, and you just want clarity and have the job done then simply use this:
def swap(text, ch1, ch2):
text = text.replace(ch2, '!',)
text = text.replace(ch1, ch2)
text = text.replace('!', ch1)
return text
This allows you to swap or simply replace chars or substring.
For example, to swap 'ab' <-> 'de' in a text:
_str = "abcdefabcdefabcdef"
print swap(_str, 'ab','de') #decabfdecabfdecabf
Loop over length of string by twos and swap:
def oddswap(st):
s = list(st)
for c in range(0,len(s),2):
t=s[c]
s[c]=s[c+1]
s[c+1]=t
return "".join(s)
giving:
>>> s
'foobar'
>>> oddswap(s)
'ofbora'
and fails on odd-length strings with an IndexError exception.
There is no need to make a list. The following works for even-length strings:
r = ''
for in in range(0, len(s), 2) :
r += s[i + 1] + s[i]
s = r
A more general answer... you can do any single pairwise swap with tuples or strings using this approach:
# item can be a string or tuple and swap can be a list or tuple of two
# indices to swap
def swap_items_by_copy(item, swap):
s0 = min(swap)
s1 = max(swap)
if isinstance(item,str):
return item[:s0]+item[s1]+item[s0+1:s1]+item[s0]+item[s1+1:]
elif isinstance(item,tuple):
return item[:s0]+(item[s1],)+item[s0+1:s1]+(item[s0],)+item[s1+1:]
else:
raise ValueError("Type not supported")
Then you can invoke it like this:
>>> swap_items_by_copy((1,2,3,4,5,6),(1,2))
(1, 3, 2, 4, 5, 6)
>>> swap_items_by_copy("hello",(1,2))
'hlelo'
>>>
Thankfully python gives empty strings or tuples for the cases where the indices refer to non existent slices.
To swap characters in a string a of position l and r
def swap(a, l, r):
a = a[0:l] + a[r] + a[l+1:r] + a[l] + a[r+1:]
return a
Example:
swap("aaabcccdeee", 3, 7) returns "aaadcccbeee"
Do you want the digits sorted? Or are you swapping odd/even indexed digits? Your example is totally unclear.
Sort:
s = '2143'
p=list(s)
p.sort()
s = "".join(p)
s is now '1234'. The trick is here that list(string) breaks it into characters.
Like so:
>>> s = "2143658709"
>>> ''.join([s[i+1] + s[i] for i in range(0, len(s), 2)])
'1234567890'
>>> s = "badcfe"
>>> ''.join([s[i+1] + s[i] for i in range(0, len(s), 2)])
'abcdef'
re.sub(r'(.)(.)',r"\2\1",'abcdef1234')
However re is a bit slow.
def swap(s):
i=iter(s)
while True:
a,b=next(i),next(i)
yield b
yield a
''.join(swap("abcdef1234"))
One more way:
>>> s='123456'
>>> ''.join([''.join(el) for el in zip(s[1::2], s[0::2])])
'214365'
>>> import ctypes
>>> s = 'abcdef'
>>> mutable = ctypes.create_string_buffer(s)
>>> for i in range(0,len(s),2):
>>> mutable[i], mutable[i+1] = mutable[i+1], mutable[i]
>>> s = mutable.value
>>> print s
badcfe
def revstr(a):
b=''
if len(a)%2==0:
for i in range(0,len(a),2):
b += a[i + 1] + a[i]
a=b
else:
c=a[-1]
for i in range(0,len(a)-1,2):
b += a[i + 1] + a[i]
b=b+a[-1]
a=b
return b
a=raw_input('enter a string')
n=revstr(a)
print n
A bit late to the party, but there is actually a pretty simple way to do this:
The index sequence you are looking for can be expressed as the sum of two sequences:
0 1 2 3 ...
+1 -1 +1 -1 ...
Both are easy to express. The first one is just range(N). A sequence that toggles for each i in that range is i % 2. You can adjust the toggle by scaling and offsetting it:
i % 2 -> 0 1 0 1 ...
1 - i % 2 -> 1 0 1 0 ...
2 * (1 - i % 2) -> 2 0 2 0 ...
2 * (1 - i % 2) - 1 -> +1 -1 +1 -1 ...
The entire expression simplifies to i + 1 - 2 * (i % 2), which you can use to join the string almost directly:
result = ''.join(string[i + 1 - 2 * (i % 2)] for i in range(len(string)))
This will work only for an even-length string, so you can check for overruns using min:
N = len(string)
result = ''.join(string[min(i + 1 - 2 * (i % 2), N - 1)] for i in range(N))
Basically a one-liner, doesn't require any iterators beyond a range over the indices, and some very simple integer math.
While the above solutions do work, there is a very simple solution shall we say in "layman's" terms. Someone still learning python and string's can use the other answers but they don't really understand how they work or what each part of the code is doing without a full explanation by the poster as opposed to "this works". The following executes the swapping of every second character in a string and is easy for beginners to understand how it works.
It is simply iterating through the string (any length) by two's (starting from 0 and finding every second character) and then creating a new string (swapped_pair) by adding the current index + 1 (second character) and then the actual index (first character), e.g., index 1 is put at index 0 and then index 0 is put at index 1 and this repeats through iteration of string.
Also added code to ensure string is of even length as it only works for even length.
DrSanjay Bhakkad post above is also a good one that works for even or odd strings and is basically doing the same function as below.
string = "abcdefghijklmnopqrstuvwxyz123"
# use this prior to below iteration if string needs to be even but is possibly odd
if len(string) % 2 != 0:
string = string[:-1]
# iteration to swap every second character in string
swapped_pair = ""
for i in range(0, len(string), 2):
swapped_pair += (string[i + 1] + string[i])
# use this after above iteration for any even or odd length of strings
if len(swapped_pair) % 2 != 0:
swapped_adj += swapped_pair[-1]
print(swapped_pair)
badcfehgjilknmporqtsvuxwzy21 # output if the "needs to be even" code used
badcfehgjilknmporqtsvuxwzy213 # output if the "even or odd" code used
One of the easiest way to swap first two characters from a String is
inputString = '2134'
extractChar = inputString[0:2]
swapExtractedChar = extractChar[::-1] """Reverse the order of string"""
swapFirstTwoChar = swapExtractedChar + inputString[2:]
# swapFirstTwoChar = inputString[0:2][::-1] + inputString[2:] """For one line code"""
print(swapFirstTwoChar)
#Works on even/odd size strings
str = '2143657'
newStr = ''
for i in range(len(str)//2):
newStr += str[i*2+1] + str[i*2]
if len(str)%2 != 0:
newStr += str[-1]
print(newStr)
#Think about how index works with string in Python,
>>> a = "123456"
>>> a[::-1]
'654321'