Comment convertir une chaîne en cas de titre en Python?

94

Exemple:

HILO -> Hilo
new york -> New York
SAN FRANCISCO -> San Francisco

Existe-t-il une bibliothèque ou une méthode standard pour effectuer cette tâche?

rêveur
la source
16
Ce n'est pas "CamelCase", c'est "Capitalize"; Lequel veux-tu?
Andrew Marshall
13
camelCase est comme ça.
Jonathan M
5
Vos exemples utilisent PascalCase.
David Betz

Réponses:

213

Pourquoi ne pas utiliser titleRight from the docs:

>>> "they're bill's friends from the UK".title()
"They'Re Bill'S Friends From The Uk"

Si vous vouliez vraiment PascalCase, vous pouvez utiliser ceci:

>>> ''.join(x for x in 'make IT pascal CaSe'.title() if not x.isspace())
'MakeItPascalCase'
Facundo Casco
la source
5
Je pense que le «r» dans «They're» devrait être en minuscules. Et le 's' dans "Bill's" doit certainement être en minuscules.
Daniel Fischer
3
@Daniel - Ce problème est noté dans la documentation pour title: "L'algorithme utilise une simple définition indépendante de la langue d'un mot sous forme de groupes de lettres consécutives. La définition fonctionne dans de nombreux contextes, mais cela signifie que les apostrophes dans les contractions et les possessifs forment les limites des mots, ce qui peut ne pas être le résultat souhaité ". Une solution possible serait d'utiliser la réponse de Laurence avec l'expression régulière r"['\w]+"pour que les apostrophes ne mettent pas fin à une correspondance (une ponctuation supplémentaire pourrait être ajoutée si nécessaire).
Andrew Clark
18
Pour mémoire, une façon plus soignée de faire le dernier exemple de CamelCase est de le faire 'make IT camel CaSe'.title().replace(' ', '').
Henry Gomersall
15
Si quelqu'un d'autre a l'impression de prendre des pilules folles, c'est PascalCase, pas camelCase.
Rob
4
Bon code mais camelCase ne commence pas par un CAPITAL. Essayez ceci: def toCamel(s): ret = ''.join(x for x in s.title() if not x.isspace()) return ret[0].lower() + ret[1:] Utilisation:toCamel("WRITE this in camelcase") 'writeThisInCamelcase'
Ron Kalian
21

Celui-ci commencerait toujours par des minuscules et supprimerait également les caractères non alphanumériques:

def camelCase(st):
    output = ''.join(x for x in st.title() if x.isalnum())
    return output[0].lower() + output[1:]
Ivan Chaer
la source
8
def capitalizeWords(s):
  return re.sub(r'\w+', lambda m:m.group(0).capitalize(), s)

re.subpeut prendre une fonction pour le "remplacement" (plutôt qu'une simple chaîne, qui est l'usage que la plupart des gens semblent connaître). Cette fonction repl sera appelée avec un re.Matchobjet pour chaque correspondance du modèle, et le résultat (qui devrait être une chaîne) sera utilisé en remplacement de cette correspondance.

Une version plus longue de la même chose:

WORD_RE = re.compile(r'\w+')

def capitalizeMatch(m):
  return m.group(0).capitalize()

def capitalizeWords(s):
  return WORD_RE.sub(capitalizeMatch, s)

Cela pré-compile le modèle (généralement considéré comme une bonne forme) et utilise une fonction nommée au lieu d'un lambda.

Laurence Gonsalves
la source
celui-ci est assez soigné, j'essaie de me familiariser avec les fonctions lambda, merci de votre aide
rêveur
1
@JohnMachin Je viens de demander parce que je pensais que l'ajout d'explications rendrait votre réponse plus complète et meilleure.
NN
@Laurence Gonsalves que fait lambda ici?
Zion
que fait lambda ici? de ce que je peux déchiffrer et de votre explication. c'est ce que j'ai compris. lorsque vous utilisez une fonction dans re.sub, chacun matchsera passé à la fonction? et puisque matchesdans les expressions régulières ont des groupes. c'est pourquoi cette ligne existe lambda m:m.group(0).capitalize()?
Zion
@Zion oui. Quand re.subon donne un appelable (par exemple: une fonction) comme "remplacement", il passe l'objet de correspondance à cet appelable, et s'attend à récupérer une chaîne qui est ce qu'il utilise réellement comme remplacement. Si vous trouvez que les lambdas sont déroutantes, la "version plus longue" fait exactement la même chose d'une manière plus verbeuse.
Laurence Gonsalves
5

Pourquoi ne pas en écrire un? Quelque chose comme celui-ci peut satisfaire vos exigences:

def FixCase(st):
    return ' '.join(''.join([w[0].upper(), w[1:].lower()]) for w in st.split())
plusieurs interfaces
la source
merci, cela a aidé complètement. Mon mauvais, je n'ai pas pensé en écrire un à la première place
rêveur
5

Remarque: pourquoi est-ce que je donne encore une autre réponse? Cette réponse est basée sur le titre de la question et la notion que camelcase est défini comme: une série de mots qui ont été concaténés (sans espaces!) De telle sorte que chacun des mots originaux commence par une majuscule (le reste étant en minuscule) à l'exception du premier mot de la série (qui est complètement minuscule). On suppose également que "toutes les chaînes" se réfère au jeu de caractères ASCII; unicode ne fonctionnerait pas avec cette solution).

Facile

Compte tenu de la définition ci-dessus, cette fonction

import re
word_regex_pattern = re.compile("[^A-Za-z]+")

def camel(chars):
  words = word_regex_pattern.split(chars)
  return "".join(w.lower() if i is 0 else w.title() for i, w in enumerate(words))

, lorsqu'il est appelé, résulterait de cette manière

camel("San Francisco")  # sanFrancisco
camel("SAN-FRANCISCO")  # sanFrancisco
camel("san_francisco")  # sanFrancisco

moins simple

Notez qu'il échoue lorsqu'il est présenté avec une chaîne déjà camel!

camel("sanFrancisco")   # sanfrancisco  <-- noted limitation

encore moins simple

Notez qu'il échoue avec de nombreuses chaînes Unicode

camel("México City")    # mXicoCity     <-- can't handle unicode

Je n'ai pas de solution pour ces cas (ou d'autres qui pourraient être introduits avec une certaine créativité). Donc, comme pour tout ce qui concerne les cordes, couvrez vos propres cas de bord et bonne chance avec unicode!

Marc
la source
Comment pouvez-vous déterminer qu'une chaîne est en cas de Camel sans connaître le sens de la phrase? Dans votre exemple "moins simple", "sanfRancisco" est le cas Camel ainsi que "itSnotcaMelcAse".
Patrice Bernassola
J'imagine que votre entrée contenait des apostraphes ou d'autres signes de ponctuation? Je devrais noter d'autres entrées ratées. Certainement une bonne prise. Quelle est votre contribution?
Marc
1
Je veux dire qu'une séquence de caractères sans espace doit être considérée comme 1 mot. Vous ne pouvez pas en extraire du travail sans connaître le sens de la phrase. Mettez "sanfRancisco" ou "itSnotcaMelcAse" comme entrée de camello () et vous verrez que la sortie sera la même.
Patrice Bernassola
Oh je vois - ouais, je pense que tu as raison. Je suradapte la solution. Je vais le mettre à jour.
Marc
4

Bibliothèque potentielle: https://pypi.org/project/stringcase/

Exemple:

import stringcase
stringcase.camelcase('foo_bar_baz') # => "fooBarBaz"

Bien qu'il soit douteux qu'il laisse des espaces dedans. (Les exemples montrent qu'il supprime de l'espace, mais il y a un problème de suivi des bogues notant qu'il les laisse dedans.)

Lol
la source
Heck oui. Je cherchais un forfait. Ce paquet a également snakecase et d'autres fonctions de conversion.
s2t2
1

il suffit d'utiliser .title (), et il convertira la première lettre de chaque mot en majuscule, reste en petit:

>>> a='mohs shahid ss'
>>> a.title()
'Mohs Shahid Ss'
>>> a='TRUE'
>>> b=a.title()
>>> b
'True'
>>> eval(b)
True
Mohammad Shahid Siddiqui
la source
1

J'aimerais ajouter ma petite contribution à ce post:

def to_camelcase(str):
  return ' '.join([t.title() for t in str.split()])
Evhz
la source
En fait, str.title () est le même et vous économisez des coûts de calcul.
Auros132
1
def camelCase(st):
    s = st.title()
    d = "".join(s.split())
    d = d.replace(d[0],d[0].lower())
    return d
Aishwarya Skandamani
la source