multiple delimiters characters python regex camelcasing

delimiters - Cómo hacer CamelCase split en python



split python 3 (7)

Lo que estaba tratando de lograr, era algo como esto:

>>> camel_case_split("CamelCaseXYZ") [''Camel'', ''Case'', ''XYZ''] >>> camel_case_split("XYZCamelCase") [''XYZ'', ''Camel'', ''Case'']

Así que busqué y encontré esta expresión regular perfecta :

(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])

Como siguiente paso lógico intenté:

>>> re.split("(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])", "CamelCaseXYZ") [''CamelCaseXYZ'']

¿Por qué esto no funciona y cómo logro el resultado de la pregunta vinculada en python?

Edición: resumen de la solución

Probé todas las soluciones provistas con algunos casos de prueba:

string: '''' nfs: [''''] casimir_et_hippolyte: [] two_hundred_success: [] kalefranz: string index out of range # with modification: either [] or [''''] string: '' '' nfs: ['' ''] casimir_et_hippolyte: [] two_hundred_success: ['' ''] kalefranz: ['' ''] string: ''lower'' all algorithms: [''lower''] string: ''UPPER'' all algorithms: [''UPPER''] string: ''Initial'' all algorithms: [''Initial''] string: ''dromedaryCase'' nfs: [''dromedary'', ''Case''] casimir_et_hippolyte: [''dromedary'', ''Case''] two_hundred_success: [''dromedary'', ''Case''] kalefranz: [''Dromedary'', ''Case''] # with modification: [''dromedary'', ''Case''] string: ''CamelCase'' all algorithms: [''Camel'', ''Case''] string: ''ABCWordDEF'' nfs: [''ABC'', ''Word'', ''DEF''] casimir_et_hippolyte: [''ABC'', ''Word'', ''DEF''] two_hundred_success: [''ABC'', ''Word'', ''DEF''] kalefranz: [''ABCWord'', ''DEF'']

En resumen, se podría decir que la solución de @kalefranz no coincide con la pregunta (consulte el último caso) y la solución de @casimir et hippolyte come un espacio único, y por lo tanto viola la idea de que una división no debe cambiar las partes individuales. La única diferencia entre las dos alternativas restantes es que mi solución devuelve una lista con la cadena vacía en una entrada de cadena vacía y la solución por @ 200_success devuelve una lista vacía. No sé cómo se encuentra la comunidad python sobre ese tema, así que digo: estoy bien con cualquiera de los dos. Y como la solución 200_success es más simple, la acepté como la respuesta correcta.


Aquí hay otra solución que requiere menos código y sin expresiones regulares complicadas:

def camel_case_split(string): bldrs = [[string[0].upper()]] for c in string[1:]: if bldrs[-1][-1].islower() and c.isupper(): bldrs.append([c]) else: bldrs[-1].append(c) return [''''.join(bldr) for bldr in bldrs]

Editar

El código anterior contiene una optimización que evita la reconstrucción de toda la cadena con cada carácter agregado. Dejando fuera esa optimización, una versión más simple (con comentarios) podría verse como

def camel_case_split2(string): # set the logic for creating a "break" def is_transition(c1, c2): return c1.islower() and c2.isupper() # start the builder list with the first character # enforce upper case bldr = [string[0].upper()] for c in string[1:]: # get the last character in the last element in the builder # note that strings can be addressed just like lists previous_character = bldr[-1][-1] if is_transition(previous_character, c): # start a new element in the list bldr.append(c) else: # append the character to the last string bldr[-1] += c return bldr


Como @nfs ha explicado, re.split() nunca se divide en una coincidencia de patrón vacía. Por lo tanto, en lugar de dividir, debe intentar encontrar los componentes que le interesan.

Aquí hay una solución que utiliza re.finditer() que emula la división:

def camel_case_split(identifier): matches = finditer(''.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)'', identifier) return [m.group(0) for m in matches]


Creo que a continuación es el optimim

Def count_word (): Return (re.findall (''[AZ]? [Az] +'', input (''ingrese su cadena''))

Imprimir (count_word ())


La documentation para re.split de re.split dice:

Tenga en cuenta que la división nunca dividirá una cadena en una coincidencia de patrón vacía.

Al ver esto:

>>> re.findall("(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])", "CamelCaseXYZ") ['''', '''']

queda claro, por qué la división no funciona como se esperaba. El módulo re encuentra coincidencias vacías, tal como lo pretende la expresión regular.

Dado que la documentación indica que esto no es un error, sino un comportamiento intencionado, debe evitarlo al intentar crear una división de fundas de camellos:

def camel_case_split(identifier): matches = finditer(''(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])'', identifier) split_string = [] # index of beginning of slice previous = 0 for match in matches: # get slice split_string.append(identifier[previous:match.start()]) # advance index previous = match.start() # get remaining string split_string.append(identifier[previous:]) return split_string


La mayoría de las veces, cuando no necesita verificar el formato de una cadena, una investigación global es más simple que una división (para el mismo resultado):

re.findall(r''[A-Z](?:[a-z]+|[A-Z]*(?=[A-Z]|$))'', ''CamelCaseXYZ'')

devoluciones

[''Camel'', ''Case'', ''XYZ'']

Para tratar con el dromedario también, puede utilizar:

re.findall(r''[A-Z]?[a-z]+|[A-Z]+(?=[A-Z]|$)'', ''camelCaseXYZ'')

Nota: (?=[AZ]|$) puede acortarse usando una negación doble (un lookahead negativo con una clase de caracteres negada): (?![^AZ])


Me topé con este caso y escribí una expresión regular para resolverlo. Debería funcionar para cualquier grupo de palabras, en realidad.

RE_WORDS = re.compile(r'''''' # Find words in a string. Order matters! [A-Z]+(?=[A-Z][a-z]) | # All upper case before a capitalized word [A-Z]?[a-z]+ | # Capitalized words / all lower case [A-Z]+ | # All upper case /d+ # Numbers '''''', re.VERBOSE)

La clave aquí es la búsqueda anticipada del primer caso posible. Unirá (y preservará) las palabras en mayúscula antes de las mayúsculas:

assert RE_WORDS.findall(''FOOBar'') == [''FOO'', ''Bar'']


Utilice re.sub() y split()

import re name = ''CamelCaseTest123'' splitted = re.sub(''(?!^)([A-Z][a-z]+)'', r'' /1'', name).split()

resultado

[''Camel'', ''Case'', ''Test123'']