Convertir la chaîne en casse de titre avec JavaScript

549

Existe-t-il un moyen simple de convertir une chaîne en casse de titre? Par exemple, john smithdevient John Smith. Je ne cherche pas quelque chose de compliqué comme la solution de John Resig , juste (espérons-le) une sorte de doublure à une ou deux lignes.

MDCore
la source
Il existe différentes méthodes, avons-nous des statistiques de performances?
theAnubhav
Veuillez vérifier cette réponse courte stackoverflow.com/a/57689168/10373693 J'espère que ce sera la réponse que vous cherchez.
Abhishek Kumar

Réponses:

740

Essaye ça:

    function toTitleCase(str) {
        return str.replace(
            /\w\S*/g,
            function(txt) {
                return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
            }
        );
    }
<form>
Input:
<br /><textarea name="input" onchange="form.output.value=toTitleCase(this.value)"  onkeyup="form.output.value=toTitleCase(this.value)"></textarea>
<br />Output:
<br /><textarea name="output" readonly onclick="select(this)"></textarea>
</form>

Greg Dean
la source
14
Quelqu'un pourrait-il expliquer pourquoi il \w\S*est utilisé à la place \w+ou \w*par exemple? Je ne sais pas pourquoi vous voudriez inclure autre chose que des espaces et donc changer Jim-Bob en Jim-bob .
martinczerwi
5
@martinCzerwi the a \w\S*également causé le Jim-bobproblème de notre côté. Utilisation \w*résolu ce problème.
Bouke
14
/([^\W_]+[^\s-]*) */grésout le Jim-Bobproblème, à savoir:jim-bob --> Jim-Bob
recursion.ninja
15
Si tel jim-bob --> Jim-Bobest votre désir, vous devriez probablement le faire /\b\w+/g. Exemple:str.replace(/\b\w+/g,function(s){return s.charAt(0).toUpperCase() + s.substr(1).toLowerCase();});
vol7ron
3
\w\S*est utilisé à la place de \w+ou \w*pour que les mots comme Don'tne soient pas modifiés Don'T, mais comme d'autres l'ont souligné, cela \w\S*cause des problèmes avec les mots avec trait d'union.
doubleDown
198

Une manière un peu plus élégante, adaptant la fonction de Greg Dean:

String.prototype.toProperCase = function () {
    return this.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
};

Appelez ça comme:

"pascal".toProperCase();
Tuan
la source
3
Gardez à l'esprit si vous avez un utilisateur avec un tiret dans son nom et qu'il entre Jo-Ann Smith, ce code le convertira en Jo-ann Smith(notez les minuscules adans Ann).
dbau
18
@daniellmb Pourquoi ne devrait-il pas modifier le prototype de String? Je pense que c'est une bonne solution. Pensez aux classes ouvertes ruby, il est parfaitement valable d'ajouter des fonctions aux classes existantes et il est largement accepté.
marco-fiset
97
@ marco-fiset Parce qu'il ne joue pas bien avec les autres! De mauvaises choses se produisent lorsque vous avez 2 bibliothèques qui tentent toutes deux de modifier des objets JavaScript natifs avec des changements incompatibles. Imaginez que jQuery et Google Maps suivent ce modèle de conception, vous ne pourriez pas avoir les deux sur la même page.
daniellmb
5
@daniellmb Un excellent point. Le fait de préfixer le nom de la méthode devrait aider à éviter cela, tout comme rendre la méthode non énumérable.
mikemaccana
60
J'ai l'impression que la déclaration "ne pas modifier les objets JavaScript natifs" est comme "ne jamais utiliser goto" ou "eval is evil". Il y a beaucoup de cas où c'est ok. Si vous avez un contrôle total sur votre projet et que vous ne prévoyez pas de le publier en tant que bibliothèque, je ne vois aucun problème avec cette méthode.
FoxMulder900
175

Essayez d'appliquer le style CSS de transformation de texte à vos contrôles.

par exemple: (text-transform: capitalize);

N'utilisez une approche JS qu'en cas de nécessité absolue.

Talha Ashfaque
la source
36
-1. Ce CSS fonctionne, mais ne fonctionne pas comme la plupart des gens l'attendent car si le texte commence en majuscules, il n'y a aucun effet. webmasterworld.com/forum83/7506.htm
whitneyland
2
@Akshar: une règle en minuscule serait remplacée par une règle de casse de titre. Étant donné que css ne modifie pas le contenu source, l'effet est que la règle minuscule est supprimée (en laissant le contenu source dans toutes les majuscules), puis la règle titlecase est appliquée (ne fait rien).
dokkaebi
42
JS est utilisé en dehors des navigateurs.
mikemaccana
4
La question était: "Existe-t-il un moyen simple de convertir une chaîne en casse de titre?" . Cette réponse ne convertit pas une chaîne. Il s'agit d'un style appliqué au sommet d'une chaîne.
kingPuppy
Si vous voulez que les données de votre base de données soient propres, afin qu'elles puissent être utilisées proprement lors du passage à des services tiers ou exportées vers CSV, alors CSS n'est pas vraiment une option. CSS est destiné aux cosmétiques, et bien qu'il ait beaucoup évolué au fil des ans et que vous puissiez l'utiliser pour résoudre ce genre de problèmes, la solution reste cosmétique et ne résout pas le problème sous-jacent.
Adam Reis
118

Voici ma version, IMO c'est facile à comprendre et élégant aussi.

var str = "foo bar baz"

console.log(

str.split(' ')
   .map(w => w[0].toUpperCase() + w.substr(1).toLowerCase())
   .join(' ')

)
// returns "Foo Bar Baz"

a8m
la source
3
Alternativement, vous pouvez minuscule la sous-chaîne dans la cartographie:str.split(' ').map(i => i[0].toUpperCase() + i.substring(1).toLowerCase()).join(' ')
Dave Land
5
Je ne suis pas d'accord avec l'appel .toLowerCase(). Des noms tels que "McDonald" ou des acronymes comme "ASAP" doivent conserver leurs caractères majuscules. Si quelqu'un a réellement passé une chaîne comme "heLLO", l'application ne doit pas supposer que les lettres majuscules sont incorrectes.
Thomas Higginbotham
1
@ThomasHigginbotham Que diriez-vous de cela? String.prototype.toTitleCase = function (blnForceLower) { var strReturn; (blnForceLower ? strReturn = this.toLowerCase() : strReturn = this); return strReturn .split(' ') .map(i => i[0].toUpperCase() + i.substr(1)) .join(' '); }
Sean Kendle
Oui, il serait préférable de fournir une option pour forcer les minuscules.
Thomas Higginbotham
1
Cela se cassera s'il strs'agit d'un seul caractère.
Madbreaks
103

Voici ma fonction qui se convertit en casse de titre mais conserve également les acronymes définis en majuscules et les mots mineurs en minuscules:

String.prototype.toTitleCase = function() {
  var i, j, str, lowers, uppers;
  str = this.replace(/([^\W_]+[^\s-]*) */g, function(txt) {
    return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
  });

  // Certain minor words should be left lowercase unless 
  // they are the first or last words in the string
  lowers = ['A', 'An', 'The', 'And', 'But', 'Or', 'For', 'Nor', 'As', 'At', 
  'By', 'For', 'From', 'In', 'Into', 'Near', 'Of', 'On', 'Onto', 'To', 'With'];
  for (i = 0, j = lowers.length; i < j; i++)
    str = str.replace(new RegExp('\\s' + lowers[i] + '\\s', 'g'), 
      function(txt) {
        return txt.toLowerCase();
      });

  // Certain words such as initialisms or acronyms should be left uppercase
  uppers = ['Id', 'Tv'];
  for (i = 0, j = uppers.length; i < j; i++)
    str = str.replace(new RegExp('\\b' + uppers[i] + '\\b', 'g'), 
      uppers[i].toUpperCase());

  return str;
}

Par exemple:

"TO LOGIN TO THIS SITE and watch tv, please enter a valid id:".toTitleCase();
// Returns: "To Login to This Site and Watch TV, Please Enter a Valid ID:"
Geoffrey Booth
la source
1
J'ai aimé le vôtre, je rencontre également des problèmes avec les nombres romains ... je l'ai juste corrigé avec I, II, III, IV, etc.
Marcelo
2
Fixé. Le regex dans la troisième ligne a été modifiée de /\w\S*/gla /([^\W_]+[^\s-]*) */gpar le commentaire de @ awashburn ci - dessus pour résoudre ce problème.
Geoffrey Booth
2
Y a-t-il un avantage à tirer de l'utilisation de votre modèle d'expression régulière /\b\w+/g, que je trouve plus compréhensible plus rapidement?
Michael - Où est Clay Shirky
2
Pas que je puisse voir, je prenais simplement la suggestion d'un autre commentateur pour résoudre le problème des mots avec trait d'union; mais votre expression régulière semble faire aussi bien, et la simplicité est toujours meilleure. Pour la postérité et les futurs visiteurs à ce poste, je viens de changer l'expression rationnelle dans la troisième ligne /([^\W_]+[^\s-]*) */gà /\b\w+/gpar @ commentaire de Michael; veuillez commenter si vous trouvez un cas où l'expression régulière plus compliquée est nécessaire.
Geoffrey Booth
1
J'ai changé l'expression régulière de 3e ligne /\b[\w-\']+/gpour autoriser les mots avec trait d'union et l'apostrophe dans les mots.
Shamasis Bhattacharya
47

Je préfère ce qui suit aux autres réponses. Il ne correspond qu'à la première lettre de chaque mot et le met en majuscule. Code plus simple, plus facile à lire et moins d'octets. Il préserve les majuscules existantes pour éviter de fausser les acronymes. Cependant, vous pouvez toujours appeler toLowerCase()votre chaîne en premier.

function title(str) {
  return str.replace(/(^|\s)\S/g, function(t) { return t.toUpperCase() });
}

Vous pouvez l'ajouter à votre prototype de chaîne qui vous permettra de 'my string'.toTitle():

String.prototype.toTitle = function() {
  return this.replace(/(^|\s)\S/g, function(t) { return t.toUpperCase() });
}

Exemple:

Tom Kay
la source
3
C'est encore plus agréable comme lambdaconst titleCase = (str) => str.replace(/\b\S/g, t => t.toUpperCase());
0xcaff
Je ne voulais pas casser IE, mais si l'application n'est pas sensible au navigateur hérité, elle pourrait être plus courte.
Tom Kay
Ce n'est qu'une solution partielle - op a demandé comment convertir une chaîne en casse de titre. Cette réponse n'accomplit pas cela pour des entrées comme NoT qUiITe.
Madbreaks
@Madbreaks La question ne stipulait pas que les entrées à casse mixte devaient être converties. Cependant, j'ai mis à jour la réponse mentionnant toLowerCase. Sachez simplement que cela briserait les acronymes. an HTML document: An HTML DocumentvsAn Html Document
Tom Kay
4
@Madbreaks Alors que votre exemple initial a été conçu, vous faites un bon point en déclarant que la sortie serait inchangée si l'entrée était capitalisée. Cela étant dit, je pense que la réponse telle toLowerCasequelle (avec la modification suggérant ) est plus flexible / utile que celle qui suppose les intentions des développeurs. Cette méthode reflète également la fonctionnalité de méthodes intégrées similaires d'autres langages tels que PHP ( ucwords) et Golang ( strings.Title). .NET ( TextInfo.ToTitleCase) fonctionne de manière intéressante pour les cas mixtes, mais laisserait également inchangées les chaînes entièrement capitalisées.
Tom Kay
20

Sans utiliser l'expression régulière juste pour référence:

String.prototype.toProperCase = function() {
  var words = this.split(' ');
  var results = [];
  for (var i = 0; i < words.length; i++) {
    var letter = words[i].charAt(0).toUpperCase();
    results.push(letter + words[i].slice(1));
  }
  return results.join(' ');
};

console.log(
  'john smith'.toProperCase()
)

Mike
la source
Merci pour la solution sans regex!
lucifer63
20

var result =
  'this is very interesting'.replace(/\b[a-z]/g, (x) => x.toUpperCase())

console.log(result) // This Is Very Interesting

simo
la source
Juste une question, la construction () sert à spécifier une correspondance sur n'importe quelle séquence d'options: c'est-à-dire que (a | b) correspond à a ou b. Que fait la construction (.)?
Michael Blackburn
Pour tous ceux qui avaient la même question, il définit un "blob" de remplacement qui est utilisé dans la section de remplacement. Les blobs sont numérotés séquentiellement, le premier () est placé dans $ 1, le second dans $ 2. J'ai trouvé ce site utile: javascript.info/tutorial/regular-expressions-methods
Michael Blackburn
Je ne suis pas en mesure de faire fonctionner ce qui précède, mais je suis loin d'être un assistant d'expression régulière. J'utilise 'string'.replace(/^(.)(.*)/,function(s,p1,p2){return p1.toUpperCase()+p2;}) encore une fois, cela ne fonctionne que pour mettre en majuscule la première lettre d'une chaîne, mais au cas où vous en auriez besoin, ma construction fonctionne.
Michael Blackburn
1
Pour une raison quelconque, FF35 semble s'étouffer '$1'.toUpperCase(), il semble que la majuscule n'ait pas été faite au moment où la valeur est affectée. Contourné en utilisant la fonction'string'.replace(/^(.){1}/,function(match) { return match.toUpperCase(); })
Contourné
Salut à tous, la réponse est fixe! Je suis presque sûr que cela fonctionnait au moment où je l'ai initialement publié. Quoi qu'il en soit, merci pour la contribution!
simo
17

Vous pouvez immédiatement toLowerCasela chaîne, puis juste toUpperCasela première lettre de chaque mot. Devient une doublure très simple:

function titleCase(str) {
  return str.toLowerCase().replace(/\b(\w)/g, s => s.toUpperCase());
}

console.log(titleCase('iron man'));
console.log(titleCase('iNcrEdible hulK'));

KevBot
la source
J'aime cette solution; agréable et simple. Il semble cependant qu'un peu de CoffeeScript se soit glissé dans votre réponse ( s => s.toUpperCase()). Ma variante est de faire ce que vous avez fait, mais en étendant l'objet String (aussi controversé que cela soit):Object.defineProperty(String.prototype, '_toProperCase', {value:function() {return this.toLowerCase().replace(/\b(\w)/g, function(t) {return t.toUpperCase()})}})
Waz
1
@Waz, merci pour les idées! Je voulais juste clarifier la =>, c'est-à-dire une fonction de flèche native (ES6), le lien saute vers les documents Mozillla sur eux qui fournit également une table de support.
KevBot
16

Juste au cas où vous seriez inquiet à propos de ces mots de remplissage, vous pouvez toujours simplement dire à la fonction ce qu'il ne faut pas mettre en majuscule.

/**
 * @param String str The text to be converted to titleCase.
 * @param Array glue the words to leave in lowercase. 
 */
var titleCase = function(str, glue){
    glue = (glue) ? glue : ['of', 'for', 'and'];
    return str.replace(/(\w)(\w*)/g, function(_, i, r){
        var j = i.toUpperCase() + (r != null ? r : "");
        return (glue.indexOf(j.toLowerCase())<0)?j:j.toLowerCase();
    });
};

J'espère que cela vous aidera.

Éditer

Si vous souhaitez gérer les principaux mots de la colle, vous pouvez garder une trace de cette w / une variable de plus:

var titleCase = function(str, glue){
    glue = !!glue ? glue : ['of', 'for', 'and', 'a'];
    var first = true;
    return str.replace(/(\w)(\w*)/g, function(_, i, r) {
        var j = i.toUpperCase() + (r != null ? r : '').toLowerCase();
        var result = ((glue.indexOf(j.toLowerCase()) < 0) || first) ? j : j.toLowerCase();
        first = false;
        return result;
    });
};
fncomp
la source
2
Vous pouvez exploser une chaîne en un tableau. Nous pourrions donc avoir des prépositions en portugais, espagnol, italien et français:glue ='de|da|del|dos|do|das|des|la|della|delli'.split('|');
Junior Mayhé
Cela n'assurera pas la capitalisation du premier mot; c'est à dire and another thingdevient and Another Thing. Juste besoin d'une manière élégante de toujours mettre en majuscule le premier mot.
Brad Koch
@BradKoch - pad avec des espaces pour que vous utilisiez 'et', 'de', etc. comme mot de recherche, puis 'And Another And Another' sera remplacé par 'And Another and Another'.
Yimin Rong
bon sauf qu'il capitalise également le texte après 'et - comme H'Dy ou Number-One
luky
Au lieu d'utiliser un opérateur ternaire, vous pouvez simplement utiliser une solution de repli: glue = glue || ['de', 'pour', 'et', 'a'];
tm2josep
14

Si l'expression régulière utilisée dans les solutions ci-dessus vous rend confus, essayez ce code:

function titleCase(str) {
  return str.split(' ').map(function(val){ 
    return val.charAt(0).toUpperCase() + val.substr(1).toLowerCase();
  }).join(' ');
}
immazharkhan
la source
aimer! pas de conversion en tableaux.
neelmeg
1
uhhh ... split ne le convertir en un tableau, vous ne voyez pas seulement comme évidemment parce que mapsignifie que vous ne devez pas utiliser la []notation
MalcolmOcean
2
C'est la même chose que la réponse de a8m de 2 ans plus tôt.
Michael - Où est Clay Shirky
1
Pauses pour les entrées à un seul caractère.
Madbreaks
1
@AlexChaffee vérifie l'historique des révisions. a8m n'a pas utilisé de fonction de flèche dans la réponse d'origine.
Merci
9

J'ai fait cette fonction qui peut gérer les noms de famille (donc ce n'est pas la casse du titre) comme "McDonald" ou "MacDonald" ou "O'Toole" ou "D'Orazio". Il ne gère cependant pas les noms allemands ou néerlandais avec "van" ou "von" qui sont souvent en minuscules ... Je pense que "de" est souvent aussi en minuscules comme "Robert de Niro". Il faudrait encore y remédier.

function toProperCase(s)
{
  return s.toLowerCase().replace( /\b((m)(a?c))?(\w)/g,
          function($1, $2, $3, $4, $5) { if($2){return $3.toUpperCase()+$4+$5.toUpperCase();} return $1.toUpperCase(); });
}
Lwangaman
la source
1
+1 pour connaître le nom. Cependant, ne gère pas correctement "macy".
brianary
C'était la seule fonction qui traitait correctement la transformation des majuscules et des minuscules en casse correcte et qui remarquait des initiales comme "US Virgin Islands".
Rodrigo Polo
Vous pouvez contourner le macyproblème en y mettant un lookahead négatif, alors cela \b((m)(a?c))?(\w)devient\b((m)(a?c))?(\w)(?!\s)
Ste
8
var toMatch = "john w. smith";
var result = toMatch.replace(/(\w)(\w*)/g, function (_, i, r) {
      return i.toUpperCase() + (r != null ? r : "");
    }
)

Semble fonctionner ... Testé avec ce qui précède, "le brun rapide, le renard? / Saute / ^ sur ^ le chien paresseux! ..." et "C: / fichiers de programme / certains fournisseurs / leur 2ème application / a file1.txt ".

Si vous voulez 2Nd au lieu de 2nd, vous pouvez passer à /([a-z])(\w*)/g .

Le premier formulaire peut être simplifié comme suit:

function toTitleCase(toTransform) {
  return toTransform.replace(/\b([a-z])/g, function (_, initial) {
      return initial.toUpperCase();
  });
}
PhiLho
la source
7

Essaye ça

String.prototype.toProperCase = function(){
    return this.toLowerCase().replace(/(^[a-z]| [a-z]|-[a-z])/g, 
        function($1){
            return $1.toUpperCase();
        }
    );
};

Exemple

var str = 'john smith';
str.toProperCase();
Maxi Baez
la source
7

Si vous pouvez utiliser des bibliothèques tierces dans votre code, lodash a une fonction d'assistance pour nous.

https://lodash.com/docs/4.17.3#startCase

_.startCase('foo bar');
// => 'Foo Bar'

_.startCase('--foo-bar--');
// => 'Foo Bar'
 
_.startCase('fooBar');
// => 'Foo Bar'
 
_.startCase('__FOO_BAR__');
// => 'FOO BAR'

waqas
la source
7

Essayez ceci, le plus court:

str.replace(/(^[a-z])|(\s+[a-z])/g, txt => txt.toUpperCase());
Vikram
la source
7

ES 6

str.split(' ')
   .map(s => s.slice(0, 1).toUpperCase() + s.slice(1).toLowerCase())
   .join(' ')

autre

str.split(' ').map(function (s) {
    return s.slice(0, 1).toUpperCase() + s.slice(1).toLowerCase();
}).join(' ')
jssridhar
la source
Juste un avertissement, devrait probablement l'être s.slice(0, 1).toUpperCase()si vous voulez toujours cette première lettre.
WindsofTime
@jssridhar, vous devez également corriger le code dans ES6.
caiosm1005
1
Casse si strest un seul personnage
Madbreaks
@jssridhar pourrait être mieux pour nous .charAt(0).toUpperCase().
roydukkey
2
duplicata de la réponse de a8m
Merci
6

La plupart de ces réponses semblent ignorer la possibilité d'utiliser le métacaractère de limite de mot (\ b). Une version plus courte de la réponse de Greg Dean l'utilisant:

function toTitleCase(str)
{
    return str.replace(/\b\w/g, function (txt) { return txt.toUpperCase(); });
}

Fonctionne également pour les noms avec trait d'union comme Jim-Bob.

lewax00
la source
2
Est une solution partielle élégante mais ne fonctionne pas avec des chaînes d'accent ou de majuscule. J'obtiens "Sofía Vergara" => "SofíA Vergara" ou "Sofía VERGARA" => "SofíA VERGARA". Le deuxième cas pourrait être résolu avec la fonction apply .toLowerCase () avant .replace (...). Le premier cas doit trouver une expression régulière correcte.
Asereware
2
Hmm, cela semble être un bug dans l'implémentation de l'expression régulière, je pense que les caractères accentués devraient être des caractères de mot (vous avez raison cependant, car cela ne fonctionne pas dans ces cas).
lewax00
\wne comprend que les caractères [A-Za-z0-9_], pas toutes les lettres. Pour cela, vous devez utiliser la catégorie Unicode \p{L}. Vous aurez besoin du /umodificateur (voir ici ) et d'une solution différente pour \b, qui ne fonctionne qu'entre \Wet \w(voir ici )
cmbuckley
6

Je pense que le plus simple est d'utiliser CSS.

function format_str(str) {
    str = str.toLowerCase();
    return '<span style="text-transform: capitalize">'+ str +'</span>';
}
Wondim
la source
J'ai mis à jour le code et l'ai testé. Cela devrait fonctionner maintenant.
Wondim
Vous ne pouvez utiliser CSS que dans une fraction des environnements où JS est utilisé, donc cette solution n'est pas viable. Les styles en ligne doivent également être évités à tout prix.
Madbreaks
5

Utilisez /\S+/gpour soutenir les signes diacritiques:

function toTitleCase(str) {
  return str.replace(/\S+/g, str => str.charAt(0).toUpperCase() + str.substr(1).toLowerCase());
}

console.log(toTitleCase("a city named örebro")); // A City Named Örebro

Cependant: " s Unshine ( y ellow)" ⇒ " S Unshine ( y ellow)"

le_m
la source
5

Je voulais ajouter ma propre réponse car j'avais besoin d'une toTitleCasefonction robuste qui prend en compte les règles de grammaire énumérées ici (article recommandé par Google). Il existe différentes règles qui dépendent de la longueur de la chaîne d'entrée. Voici la fonction + tests unitaires.

La fonction consolide également les espaces et supprime les caractères spéciaux (modifiez l'expression régulière selon vos besoins)

Fonction toTitleCase

const toTitleCase = (str) => {
  const articles = ['a', 'an', 'the'];
  const conjunctions = ['for', 'and', 'nor', 'but', 'or', 'yet', 'so'];
  const prepositions = [
    'with', 'at', 'from', 'into','upon', 'of', 'to', 'in', 'for',
    'on', 'by', 'like', 'over', 'plus', 'but', 'up', 'down', 'off', 'near'
  ];

  // The list of spacial characters can be tweaked here
  const replaceCharsWithSpace = (str) => str.replace(/[^0-9a-z&/\\]/gi, ' ').replace(/(\s\s+)/gi, ' ');
  const capitalizeFirstLetter = (str) => str.charAt(0).toUpperCase() + str.substr(1);
  const normalizeStr = (str) => str.toLowerCase().trim();
  const shouldCapitalize = (word, fullWordList, posWithinStr) => {
    if ((posWithinStr == 0) || (posWithinStr == fullWordList.length - 1)) {
      return true;
    }

    return !(articles.includes(word) || conjunctions.includes(word) || prepositions.includes(word));
  }

  str = replaceCharsWithSpace(str);
  str = normalizeStr(str);

  let words = str.split(' ');
  if (words.length <= 2) { // Strings less than 3 words long should always have first words capitalized
    words = words.map(w => capitalizeFirstLetter(w));
  }
  else {
    for (let i = 0; i < words.length; i++) {
      words[i] = (shouldCapitalize(words[i], words, i) ? capitalizeFirstLetter(words[i], words, i) : words[i]);
    }
  }

  return words.join(' ');
}

Tests unitaires pour garantir l'exactitude

import { expect } from 'chai';
import { toTitleCase } from '../../src/lib/stringHelper';

describe('toTitleCase', () => {
  it('Capitalizes first letter of each word irrespective of articles, conjunctions or prepositions if string is no greater than two words long', function(){
    expect(toTitleCase('the dog')).to.equal('The Dog'); // Capitalize articles when only two words long
    expect(toTitleCase('for all')).to.equal('For All'); // Capitalize conjunctions when only two words long
    expect(toTitleCase('with cats')).to.equal('With Cats'); // Capitalize prepositions when only two words long
  });

  it('Always capitalize first and last words in a string irrespective of articles, conjunctions or prepositions', function(){
    expect(toTitleCase('the beautiful dog')).to.equal('The Beautiful Dog');
    expect(toTitleCase('for all the deadly ninjas, be it so')).to.equal('For All the Deadly Ninjas Be It So');
    expect(toTitleCase('with cats and dogs we are near')).to.equal('With Cats and Dogs We Are Near');
  });

  it('Replace special characters with space', function(){
    expect(toTitleCase('[wolves & lions]: be careful')).to.equal('Wolves & Lions Be Careful');
    expect(toTitleCase('wolves & lions, be careful')).to.equal('Wolves & Lions Be Careful');
  });

  it('Trim whitespace at beginning and end', function(){
    expect(toTitleCase(' mario & Luigi superstar saga ')).to.equal('Mario & Luigi Superstar Saga');
  });

  it('articles, conjunctions and prepositions should not be capitalized in strings of 3+ words', function(){
    expect(toTitleCase('The wolf and the lion: a tale of two like animals')).to.equal('The Wolf and the Lion a Tale of Two like Animals');
    expect(toTitleCase('the  three Musketeers  And plus ')).to.equal('The Three Musketeers and Plus');
  });
});

Veuillez noter que je retire pas mal de caractères spéciaux des chaînes fournies. Vous devrez modifier le regex pour répondre aux exigences de votre projet.

moment dipolaire
la source
Je préfère cette solution car elle s'occupe vraiment de la casse du titre. Ce n'est pas "Autant en emporte le vent", c'est "Autant en emporte le vent"
russellmania
5
"john f. kennedy".replace(/\b\S/g, t => t.toUpperCase())
Proximo
la source
1
Fonctionne pour l'échantillon et o'henry, mais fait des trucs bizarres avec horse's mouth.
Michael - Où est Clay Shirky le
"john f. kennEdy".toLowerCase().replace(/\b\S/g, t => t.toUpperCase())mieux w
w3debugger
Je ne voulais pas modifier la réponse de @ Proximo: les \bet \Ssont des classes de caractères spéciaux désignant les «limites de mots» et les «caractères simples non blancs. Ainsi, l'expression régulière correspond à chaque caractère suivant une limite de mot et met en majuscule ce caractère en appliquant la fonction de flèche donnée.
Jens
4

En prenant la solution "lewax00", j'ai créé cette solution simple qui force à "w" en commençant par l'espace ou "w" qui initie le mot, mais n'est pas en mesure de supprimer les espaces intermédiaires supplémentaires.

"SOFÍA vergara".toLowerCase().replace(/\b(\s\w|^\w)/g, function (txt) { return txt.toUpperCase(); });

Le résultat est "Sofía Vergara".

Asereware
la source
4

Voici ma fonction qui s'occupe des caractères accentués (important pour le français!) Et qui peut activer / désactiver la gestion des exceptions basses. J'espère que cela pourra aider.

String.prototype.titlecase = function(lang, withLowers = false) {
    var i, string, lowers, uppers;

    string = this.replace(/([^\s:\-'])([^\s:\-']*)/g, function(txt) {
        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
    }).replace(/Mc(.)/g, function(match, next) {
        return 'Mc' + next.toUpperCase();
    });

    if (withLowers) {
        if (lang == 'EN') {
            lowers = ['A', 'An', 'The', 'At', 'By', 'For', 'In', 'Of', 'On', 'To', 'Up', 'And', 'As', 'But', 'Or', 'Nor', 'Not'];
        }
        else {
            lowers = ['Un', 'Une', 'Le', 'La', 'Les', 'Du', 'De', 'Des', 'À', 'Au', 'Aux', 'Par', 'Pour', 'Dans', 'Sur', 'Et', 'Comme', 'Mais', 'Ou', 'Où', 'Ne', 'Ni', 'Pas'];
        }
        for (i = 0; i < lowers.length; i++) {
            string = string.replace(new RegExp('\\s' + lowers[i] + '\\s', 'g'), function(txt) {
                return txt.toLowerCase();
            });
        }
    }

    uppers = ['Id', 'R&d'];
    for (i = 0; i < uppers.length; i++) {
        string = string.replace(new RegExp('\\b' + uppers[i] + '\\b', 'g'), uppers[i].toUpperCase());
    }

    return string;
}
Ouatataz
la source
4

Nous avons eu une discussion ici au bureau et nous pensons qu'essayer de corriger automatiquement la façon dont les gens saisissent les noms de la manière actuelle que vous voulez qu'il fasse est semé d'embûches.

Nous avons trouvé plusieurs cas où différents types de capitalisation automatique se désagrègent et ce sont uniquement pour les noms anglais, chaque langue a ses propres complexités.

Problèmes de mise en majuscule de la première lettre de chaque nom:

• Les acronymes tels qu'IBM ne peuvent pas être saisis, se transformeraient en Ibm.

• Le nom McDonald se transformerait en Mcdonald, ce qui est incorrect, la même chose est MacDonald aussi.

• Les noms à double canon tels que Marie-Tonks deviendraient Marie-tonks.

• Des noms comme O'Connor se transformeraient en O'connor.

Pour la plupart d'entre eux, vous pouvez écrire des règles personnalisées pour y faire face, cependant, cela a toujours des problèmes avec Acronymes comme avant et vous obtenez un nouveau problème:

• L'ajout d'une règle pour fixer les noms avec Mac comme MacDonald, ferait que les noms de rupture comme Macy le transforment en MacY.

La seule solution que nous avons trouvée qui n'est jamais incorrecte est de mettre en majuscule chaque lettre qui est une méthode de force brute que le DBS semble également utiliser.

Donc, si vous voulez automatiser le processus, il est presque impossible de se passer d'un dictionnaire de chaque nom et mot et de la façon dont il devrait être capitalisé.Si vous n'avez pas de règle qui couvre tout, ne l'utilisez pas comme il ne fera qu'ennuyer vos utilisateurs et inciter les personnes qui souhaitent saisir correctement leur nom à aller ailleurs.

jjr2000
la source
4

voici une autre solution utilisant css (et javascript, si le texte que vous souhaitez transformer est en majuscule):

html

<span id='text'>JOHN SMITH</span>

js

var str = document.getElementById('text').innerHtml;
var return_text = str.toLowerCase();

css

#text{text-transform:capitalize;}
henrie
la source
3

Pour ceux d'entre nous qui ont peur des expressions régulières (lol):

function titleCase(str)
{
    var words = str.split(" ");
    for ( var i = 0; i < words.length; i++ )
    {
        var j = words[i].charAt(0).toUpperCase();
        words[i] = j + words[i].substr(1);
    }
    return words.join(" ");
}

lashja
la source
3

Ma solution monoligne:

String.prototype.capitalizeWords = function() {
    return this.split(" ").map(function(ele){ return ele[0].toUpperCase() + ele.slice(1).toLowerCase();}).join(" ");
};

Ensuite, vous pouvez appeler la méthode capitalizeWords()sur n'importe quelle chaîne. Par exemple:

var myS = "this actually works!";
myS.capitalizeWords();

>>> This Actually Works

Mon autre solution:

function capitalizeFirstLetter(word) {
    return word[0].toUpperCase() + word.slice(1).toLowerCase();
}
String.prototype.capitalizeAllWords = function() {
    var arr = this.split(" ");
    for(var i = 0; i < arr.length; i++) {
        arr[i] = capitalizeFirstLetter(arr[i]);
    }
    return arr.join(" ");
};

Ensuite, vous pouvez appeler la méthode capitalizeWords()sur n'importe quelle chaîne. Par exemple:

var myStr = "this one works too!";
myStr.capitalizeWords();

>>> This One Works Too

Solution alternative basée sur la réponse de Greg Dean:

function capitalizeFirstLetter(word) {
    return word[0].toUpperCase() + word.slice(1).toLowerCase();
}
String.prototype.capitalizeWords = function() {
    return this.replace(/\w\S*/g, capitalizeFirstLetter);
};

Ensuite, vous pouvez appeler la méthode capitalizeWords()sur n'importe quelle chaîne. Par exemple:

var myString = "yes and no";
myString.capitalizeWords()

>>> Yes And No
Fouad Boukredine
la source
3

Surpris de voir que personne n'a mentionné l'utilisation du paramètre de repos. Voici un simple liner qui utilise les paramètres ES6 Rest.

let str="john smith"
str=str.split(" ").map(([firstChar,...rest])=>firstChar.toUpperCase()+rest.join("").toLowerCase()).join(" ")
console.log(str)

kapil pandey
la source
2

Ceci est basé sur ma solution pour Bonfire "Title Case" de FreeCodeCamp , qui vous oblige à convertir d'abord la chaîne donnée en minuscules et ensuite convertir chaque caractère procédant d'un espace en majuscules.

Sans utiliser l'expression régulière:

function titleCase(str) {
 return str.toLowerCase().split(' ').map(function(val) { return val.replace(val[0], val[0].toUpperCase()); }).join(' ');
}
Jamesy Dimmick May
la source