minusculas - separar palabra en letras python
Dividir una cadena en letras mayúsculas (12)
¿Cuál es la forma pitónica de dividir una cadena antes de las apariciones de un conjunto dado de caracteres?
Por ejemplo, quiero dividir ''TheLongAndWindingRoad''
en cualquier aparición de una letra mayúscula (posiblemente excepto la primera), y obtener [''The'', ''Long'', ''And'', ''Winding'', ''Road'']
.
Edición: También debería dividir las ocurrencias individuales, es decir, de ''ABC''
Me gustaría obtener [''A'', ''B'', ''C'']
.
Aquí hay una solución regex alternativa. El problema se puede volver a escribir como "¿Cómo inserto un espacio antes de cada letra en mayúscula, antes de hacer la división":
>>> s = "TheLongAndWindingRoad ABC A123B45"
>>> re.sub( r"([A-Z])", r" /1", s).split()
[''The'', ''Long'', ''And'', ''Winding'', ''Road'', ''A'', ''B'', ''C'', ''A123'', ''B45'']
Esto tiene la ventaja de preservar todos los caracteres que no son espacios en blanco, que la mayoría de las otras soluciones no lo hacen.
Desafortunadamente, no es posible dividir en una coincidencia de ancho cero en Python. Pero puedes usar re.findall
en re.findall
lugar:
>>> import re
>>> re.findall(''[A-Z][^A-Z]*'', ''TheLongAndWindingRoad'')
[''The'', ''Long'', ''And'', ''Winding'', ''Road'']
>>> re.findall(''[A-Z][^A-Z]*'', ''ABC'')
[''A'', ''B'', ''C'']
Esto es posible con la herramienta more_itertools.split_before
.
import more_itertools as mit
iterable = "TheLongAndWindingRoad"
[ "".join(i) for i in mit.split_before(iterable, lambda s: s.isupper())]
# [''The'', ''Long'', ''And'', ''Winding'', ''Road'']
También debería dividir las ocurrencias individuales, es decir, de
''ABC''
me gustaría obtener[''A'', ''B'', ''C'']
.
iterable = "ABC"
[ "".join(i) for i in mit.split_before(iterable, lambda s: s.isupper())]
# [''A'', ''B'', ''C'']
more_itertools
es un paquete de terceros con más de 60 herramientas útiles que incluyen implementaciones para todas las recetas originales de itertools , lo que evita su implementación manual.
Otro sin expresiones regulares y la capacidad de mantener mayúsculas contiguas si se desea
def split_on_uppercase(s, keep_contiguous=False):
"""
Args:
s (str): string
keep_contiguous (bool): flag to indicate we want to
keep contiguous uppercase chars together
Returns:
"""
string_length = len(s)
is_lower_around = (lambda: s[i-1].islower() or
string_length > (i + 1) and s[i + 1].islower())
start = 0
parts = []
for i in range(1, string_length):
if s[i].isupper() and (not keep_contiguous or is_lower_around()):
parts.append(s[start: i])
start = i
parts.append(s[start:])
return parts
>>> split_on_uppercase(''theLongWindingRoad'')
[''the'', ''Long'', ''Winding'', ''Road'']
>>> split_on_uppercase(''TheLongWindingRoad'')
[''The'', ''Long'', ''Winding'', ''Road'']
>>> split_on_uppercase(''TheLongWINDINGRoadT'', True)
[''The'', ''Long'', ''WINDING'', ''Road'', ''T'']
>>> split_on_uppercase(''ABC'')
[''A'', ''B'', ''C'']
>>> split_on_uppercase(''ABCD'', True)
[''ABCD'']
>>> split_on_uppercase('''')
['''']
>>> split_on_uppercase(''hello world'')
[''hello world'']
Reemplace cada letra mayúscula ''L'' en el dado con un espacio vacío más esa letra "L".
def splitAtUpperCase(text):
result = ""
for char in text:
if char.isupper():
result += " " + char
else:
result += char
return result.split()
En el caso del ejemplo dado:
print(splitAtUpperCase(''TheLongAndWindingRoad''))
[''The'', ''Long'', ''And'', ''Winding'', ''Road'']
También podría usar un bucle for
con una sentencia if
como
def splitAtUpperCase(s):
for i in range(len(s)-1)[::-1]:
if s[i].isupper() and s[i+1].islower():
s = s[:i]+'' ''+s[i:]
if s[i].isupper() and s[i-1].islower():
s = s[:i]+'' ''+s[i:]
return '' ''.join(s.split)
print(splitAtUpperCase(TheLongAndWindingRoad)
>>>> ''The Long And Winding Road''
Gracias.
Solución alternativa (si no te gustan las expresiones regulares explícitas):
s = ''TheLongAndWindingRoad''
pos = [i for i,e in enumerate(s) if e.isupper()]
parts = []
for j in xrange(len(pos)):
try:
parts.append(s[pos[j]:pos[j+1]])
except IndexError:
parts.append(s[pos[j]:])
print parts
Una forma alternativa sin usar expresiones regulares o enumerar:
word = ''TheLongAndWindingRoad''
list = [x for x in word]
for char in list:
if char != list[0] and char.isupper():
list[list.index(char)] = '' '' + char
fin_list = ''''.join(list).split('' '')
Creo que es más claro y sencillo sin encadenar demasiados métodos o usar una larga lista de comprensión que puede ser difícil de leer.
Una forma alternativa utilizando enumerate
y isupper()
Código:
strs = ''TheLongAndWindingRoad''
ind =0
count =0
new_lst=[]
for index, val in enumerate(strs[1:],1):
if val.isupper():
new_lst.append(strs[ind:index])
ind=index
if ind<len(strs):
new_lst.append(strs[ind:])
print new_lst
Salida:
[''The'', ''Long'', ''And'', ''Winding'', ''Road'']
Una variación de la solución de @ChristopheD.
s = ''TheLongAndWindingRoad''
pos = [i for i,e in enumerate(s+''A'') if e.isupper()]
parts = [s[pos[j]:pos[j+1]] for j in xrange(len(pos)-1)]
print parts
import re
filter(None, re.split("([A-Z][^A-Z]*)", "TheLongAndWindingRoad"))
o
[s for s in re.split("([A-Z][^A-Z]*)", "TheLongAndWindingRoad") if s]
src = ''TheLongAndWindingRoad''
glue = '' ''
result = ''''.join(glue + x if x.isupper() else x for x in src).strip(glue).split(glue)
>>> import re
>>> re.findall(''[A-Z][a-z]*'', ''TheLongAndWindingRoad'')
[''The'', ''Long'', ''And'', ''Winding'', ''Road'']
>>> re.findall(''[A-Z][a-z]*'', ''SplitAString'')
[''Split'', ''A'', ''String'']
>>> re.findall(''[A-Z][a-z]*'', ''ABC'')
[''A'', ''B'', ''C'']
Si desea que "It''sATest"
divida a ["It''s", ''A'', ''Test'']
cambie el rexeg a "[AZ][a-z'']*"