I have a variable cuenta
that has the value "3!+4!"
andenter, I want to find all the ones !
(with their respective numbers) that exist to change them by the factorial function of math(math.factorial()), I was going to use re.sub(r"\d+\!")
it to find it but I don't know how to say what find, let's call it x, I perform the operation factorial(eval(x[0:len(x-1)]))
so that it returns cuenta = 6+24
.
I was trying to use something like:
re.sub(x=r"\d+\!", factorial(eval(x[0:len(x)-1])), cuenta)
where in x I save what was found and replace it with the factorial only of the number, but it won't let me.
any idea what i can do?
The following occurs to me:
Explanation
The regular expression
(\d+)!
will match any sequence of digits that has an exclamation mark at the end, and also , thanks to the parentheses, it will capture what the sequence of digits was.Using I
re.sub()
replace all the matches of the regular expression by pairs of braces. Note that this replaces the entire match, which includes the exclamation point, and not just the captured group that would not include it. In the example, it would return'{}+{}+({}/{})'
, which leaves a template ready to later use with.format()
, and thus be able to replace each pair of braces with the corresponding factorial.Using
re.findall()
I get a list with all captured groups. In the example the resulting list would be['3', '4', '5', '3']
, which is stored in the variablenumeros
. Contains the numbers whose factorial is to be computed.By means of the generating expression I generate
factorial(int(n)) for n in numeros
the corresponding factorials of the numbers in question. In our case that expression will generate the quantities6, 24, 120, 6
.Using the operator
*
in front of the generator expression, I turn that iterable into a separate series of parameters, which I pass toformat()
.I apply
.format()
that to the previously prepared template that had pairs of braces in strategic places, and thus I obtain the final string'6+24+(120/6)'
It should be noted that you can put everything on one line, but frankly I think it gets too cryptic (and already was without this). As a curiosity, the line would be:
Extension
At the request of the user, I expand the mission of the
*
.This is an operator that python has that allows you to "unpack" a list or a tuple (or in this particular example a generator expression) and convert it into a series of arguments separated by commas. The best way to explain it will be with an example.
When you have a function that receives, for example, three parameters, the normal way to call it would be:
funcion(1, 2, 3)
. In this case, the parameters are said to be positional , since they are assigned to those declared in the function according to the position they occupy. That is, if the function is declared with adef funcion(a,b,c)
, the above call will assign 1 to parametera
, 2 to ,b
and 3 toc
(Python also has another way of calling the function where they are not assigned by position, but by name).Well, now imagine that you have a list
l = [1,2,3]
and you want to call the function passing the elements of that list as parameters. Naturallyfuncion(l)
it won't work, as that would assign the entire list to the parametera
and leaveb
yc
empty.The solution, if you don't know the operator
*
, would be to dofuncion(l[0], l[1], l[2])
, but the operator*
allows for something more concise and elegant:funcion(*l)
. The result is that the listl
is "unpacked" and each of its values becomes a separate parameter.This also works for functions that take a variable number of parameters, such as
str.format()
. The list in this case can have any number of elements. It also works ifl
, instead of a list, is a tuple or a generator expression.In the code of my answer, the variable
template
has{}
four positions, soformat
four parameters would have to be passed to it. The listnumeros
has four elements, so the generator expression will return four factorials, and the*
will convert it to the four parameters you.format()
need to fill all four{}
in thetemplate
.Note that this is tremendously flexible and powerful, as it all depends on what the
cadena
initial would have been, and it automatically "adapts" to any number of factorials this string might contain, since if there were only three factorial expressions in it, ittemplate
would have only three{}
andnumeros
only three items. So everything fits again. You couldn't have done this without the operator*
.