output = input_text.replace('una', '1')
It should do a replacement of the substring "una"
by the string "1"
, but only in certain cases. The problem is that I am having a hard time finding the indicated regex pattern or a concatenation of patterns that allow us to obtain these replacements of "una"
by "1"
.
Here I have added 9 examples where this regex should operate
#example 1
input_text = "ashashj a la una y una jhasjhdjhas" #input
output = "ashashj a la 1 y 1 jhasjhdjhas" #the expected output string
#example 2
input_text = "ajshdjhas a las una y una hsdhjds"
output = "ajshdjhas a las 1 y 1 hsdhjds"
#example 3
input_text = "A la una y cuarto hjjhhj"
output = "A la 1 y cuarto hjjhhj"
#example 4
input_text = "a las una y media hjjhsssshj"
output = "a las 1 y media hjjhsssshj"
#example 5
input_text = "A la una y menos cuarto hjjhhj"
output = "A la 1 y menos cuarto hjjhhj"
#example 6
input_text = "A las una en punto ashjs"
output = "A las 1 en punto ashjs"
#example 7
input_text = "asas a la una en punto ajs"
output = "asas a la 1 en punto ajs"
#example 8
input_text = "hay que colocar una buena antena... algunas ya estaran entre la una y las una y media, pero con estar a eso de la una y una esta bien para alguna. A eso de la una! deberia estar como mucho a la una y poco mas, almenos una de ellas"
output = "hay que colocar una buena antena... algunas ya estaran entre la 1 y las 1 y media, pero con estar a eso de la 1 y 1 esta bien para alguna. A eso de la 1! deberia estar como mucho a la 1 y poco mas, almenos una de ellas"
#example 9
input_text = "unas o algunas de ellas, ya estan entre la una, cerca de la una y las una y media, pero con estar a eso de la una; esta bien para llegar temprano, pero no quiero pasarme de la una y una."
output = "unas o algunas de ellas, ya estan entre la 1, cerca de la 1 y las 1 y media, pero con estar a eso de la 1; esta bien para llegar temprano, pero no quiero pasarme de la 1 y 1."
I have thought to do it in 2 regex patterns, maybe something like that...
r"(a las|a la|:)\s*una"
and then this pattern
r"una\s*(y cuarto|y media|y menos cuarto|menos cuarto|:)"
, and if at least one of them is true... then do the replacement "una"
with "1"
CodePudding user response:
This is an interesting question because it requires some advanced tweaks to solve it. Let us first create some automatic testing (this is not a unit-test but you could easily create one from it):
input_text = ["ashashj a la una y una jhasjhdjhas",
"ajshdjhas a las una y una hsdhjds",
"A la una y cuarto hjjhhj",
"a las una y media hjjhsssshj",
"A la una y menos cuarto hjjhhj",
"A las una en punto ashjs",
"asas a la una en punto ajs",
"hay que colocar una buena antena... algunas ya estaran entre la una y las una y media, pero con estar a eso de la una y una esta bien para alguna. A eso de la una! deberia estar como mucho a la una y poco mas, almenos una de ellas",
"unas o algunas de ellas, ya estan entre la una, cerca de la una y las una y media, pero con estar a eso de la una; esta bien para llegar temprano, pero no quiero pasarme de la una y una."]
output = ["ashashj a la 1 y 1 jhasjhdjhas",
"ajshdjhas a las 1 y 1 hsdhjds",
"A la 1 y cuarto hjjhhj",
"a las 1 y media hjjhsssshj",
"A la 1 y menos cuarto hjjhhj",
"A las 1 en punto ashjs",
"asas a la 1 en punto ajs",
"hay que colocar una buena antena... algunas ya estaran entre la 1 y las 1 y media, pero con estar a eso de la 1 y 1 esta bien para alguna. A eso de la 1! deberia estar como mucho a la 1 y poco mas, almenos una de ellas",
"unas o algunas de ellas, ya estan entre la 1, cerca de la 1 y las 1 y media, pero con estar a eso de la 1; esta bien para llegar temprano, pero no quiero pasarme de la 1 y 1."]
for ogl, des in zip(input_text, output):
txt = re.sub(pattern, "1", ogl)
assert(txt == des)
We now simply loop over the examples and assert that they are equal. If no error is raised, you've defined a suitable pattern. The only thing left to define is pattern
.
Here comes the advanced thinking:
- we want to replace all occurrences of the character sequence
"una"
, but only - if it is preceded by
"la "
,"las "
or"y "
(always with a widespace), and - followed by a widespace, or an end of sentence character (
.
!
?
), or a split clause sign (,
;
:
) -- note that many of them need to be escaped as they are used to indicate special patterns)
Let's put that into a pattern:
pattern = "(?<=((las?)|(y))\s)una(?=[\.\?\!\:,;\s])"
We can translate the second requirement to "((las?)|(y))\s)"
but the trick is to use "(?<=...)"
that indicates a non-consumed look-ahead preceding the desired character sequence. The problem is that the standard re
-package cannot cope with such a look-ahead if it is of variable length! (i.e. if you use ?
or |
). Load the advanced regex
package (note that you need to install it via pip install regex
): import regex as re
The third requirement can be achieved with the pattern (?=[\.\?\!\:,;\s])
that again produces a look-ahead after the desired sequence. Again, it does not consume the string which simply says that it requires those characters to be present in the string but they are not replaced.
For the sake of conciseness the entire code in one box:
import re
input_text = ["ashashj a la una y una jhasjhdjhas",
"ajshdjhas a las una y una hsdhjds",
"A la una y cuarto hjjhhj",
"a las una y media hjjhsssshj",
"A la una y menos cuarto hjjhhj",
"A las una en punto ashjs",
"asas a la una en punto ajs",
"hay que colocar una buena antena... algunas ya estaran entre la una y las una y media, pero con estar a eso de la una y una esta bien para alguna. A eso de la una! deberia estar como mucho a la una y poco mas, almenos una de ellas",
"unas o algunas de ellas, ya estan entre la una, cerca de la una y las una y media, pero con estar a eso de la una; esta bien para llegar temprano, pero no quiero pasarme de la una y una."]
output = ["ashashj a la 1 y 1 jhasjhdjhas",
"ajshdjhas a las 1 y 1 hsdhjds",
"A la 1 y cuarto hjjhhj",
"a las 1 y media hjjhsssshj",
"A la 1 y menos cuarto hjjhhj",
"A las 1 en punto ashjs",
"asas a la 1 en punto ajs",
"hay que colocar una buena antena... algunas ya estaran entre la 1 y las 1 y media, pero con estar a eso de la 1 y 1 esta bien para alguna. A eso de la 1! deberia estar como mucho a la 1 y poco mas, almenos una de ellas",
"unas o algunas de ellas, ya estan entre la 1, cerca de la 1 y las 1 y media, pero con estar a eso de la 1; esta bien para llegar temprano, pero no quiero pasarme de la 1 y 1."]
for ogl, des in zip(input_text, output):
txt = re.sub("(?<=((las?)|(y))\s)una(?=[\.\?\!\:,;\s])", "1", ogl)
assert(txt == des)
Since it doesn't throw an error, it suits all your examples.