En JavaScript, comment écrirait-on une fonction qui convertit un nombre donné [edit: entier positif} _] (inférieur à 100 milliards) en une abréviation à 3 lettres - où 0-9 et az/AZ comptent comme une lettre, mais le point (comme il est si petit dans de nombreuses polices proportionnelles) ne serait pas, et serait ignoré en termes de limite de lettre?
Cette question est liée à ce fil utile , mais ce n'est pas la même chose; par exemple, où cette fonction tournerait, par exemple "123456 -> 1.23k" ("123.5k" étant 5 lettres) Je cherche quelque chose qui "123456 -> 0.1m" ("0 [.] 1m" étant 3 lettres). Par exemple, il s’agirait de la sortie de la fonction espérée (valeur de retour idéale originale à gauche, à gauche):
0 "0"
12 "12"
123 "123"
1234 "1.2k"
12345 "12k"
123456 "0.1m"
1234567 "1.2m"
12345678 "12m"
123456789 "0.1b"
1234567899 "1.2b"
12345678999 "12b"
Merci!
Mise à jour: Merci! Une réponse est disponible et fonctionne conformément aux exigences lorsque les modifications suivantes sont apportées:
function abbreviateNumber(value) {
var newValue = value;
if (value >= 1000) {
var suffixes = ["", "k", "m", "b","t"];
var suffixNum = Math.floor( (""+value).length/3 );
var shortValue = '';
for (var precision = 2; precision >= 1; precision--) {
shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
if (dotLessShortValue.length <= 2) { break; }
}
if (shortValue % 1 != 0) shortNum = shortValue.toFixed(1);
newValue = shortValue+suffixes[suffixNum];
}
return newValue;
}
Je crois que la solution de ninjagecko n'est pas tout à fait conforme à la norme que vous souhaitiez. La fonction suivante fait:
function intToString (value) {
var suffixes = ["", "k", "m", "b","t"];
var suffixNum = Math.floor((""+value).length/3);
var shortValue = parseFloat((suffixNum != 0 ? (value / Math.pow(1000,suffixNum)) : value).toPrecision(2));
if (shortValue % 1 != 0) {
var shortNum = shortValue.toFixed(1);
}
return shortValue+suffixes[suffixNum];
}
Pour les valeurs supérieures à 99 000 milliards de lettres, aucune lettre ne sera ajoutée, ce qui peut être facilement corrigé en ajoutant au tableau des suffixes.
Edit by Philipp suit: Les modifications suivantes s’adaptent parfaitement à toutes les exigences!
function abbreviateNumber(value) {
var newValue = value;
if (value >= 1000) {
var suffixes = ["", "k", "m", "b","t"];
var suffixNum = Math.floor( (""+value).length/3 );
var shortValue = '';
for (var precision = 2; precision >= 1; precision--) {
shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
if (dotLessShortValue.length <= 2) { break; }
}
if (shortValue % 1 != 0) shortNum = shortValue.toFixed(1);
newValue = shortValue+suffixes[suffixNum];
}
return newValue;
}
Cela gère également de très grandes valeurs et est un peu plus succinct et efficace.
abbreviate_number = function(num, fixed) {
if (num === null) { return null; } // terminate early
if (num === 0) { return '0'; } // terminate early
fixed = (!fixed || fixed < 0) ? 0 : fixed; // number of decimal places to show
var b = (num).toPrecision(2).split("e"), // get power
k = b.length === 1 ? 0 : Math.floor(Math.min(b[1].slice(1), 14) / 3), // floor at decimals, ceiling at trillions
c = k < 1 ? num.toFixed(0 + fixed) : (num / Math.pow(10, k * 3) ).toFixed(1 + fixed), // divide by power
d = c < 0 ? c : Math.abs(c), // enforce -0 is 0
e = d + ['', 'K', 'M', 'B', 'T'][k]; // append power
return e;
}
Résultats:
for(var a='', i=0; i < 14; i++){
a += i;
console.log(a, abbreviate_number(parseInt(a),0));
console.log(-a, abbreviate_number(parseInt(-a),0));
}
0 0
-0 0
01 1
-1 -1
012 12
-12 -12
0123 123
-123 -123
01234 1.2K
-1234 -1.2K
012345 12.3K
-12345 -12.3K
0123456 123.5K
-123456 -123.5K
01234567 1.2M
-1234567 -1.2M
012345678 12.3M
-12345678 -12.3M
0123456789 123.5M
-123456789 -123.5M
012345678910 12.3B
-12345678910 -12.3B
01234567891011 1.2T
-1234567891011 -1.2T
0123456789101112 123.5T
-123456789101112 -123.5T
012345678910111213 12345.7T
-12345678910111212 -12345.7T
Je pense que vous ne pouvez pas essayer ceci numeraljs/
Si vous voulez convertir 1000 en 1k
console.log(numeral(1000).format('0a'));
et si vous voulez convertir 123400 en 123.4k essayez ceci
console.log(numeral(123400).format('0.0a'));
Voici ce que je pense est une solution assez élégante. Il ne tente pas de traiter les nombres négatifs :
const COUNT_ABBRS = [ '', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' ];
function formatCount(count, withAbbr = false, decimals = 2) {
const i = 0 === count ? count : Math.floor(Math.log(count) / Math.log(1000));
let result = parseFloat((count / Math.pow(1000, i)).toFixed(decimals));
if(withAbbr) {
result += `${COUNT_ABBRS[i]}`;
}
return result;
}
Exemples :
formatCount(1000, true);
=> '1k'
formatCount(100, true);
=> '100'
formatCount(10000, true);
=> '10k'
formatCount(10241, true);
=> '10.24k'
formatCount(10241, true, 0);
=> '10k'
formatCount(10241, true, 1)
=> '10.2k'
formatCount(1024111, true, 1)
=> '1M'
formatCount(1024111, true, 2)
=> '1.02M'
D'après ma réponse à https://stackoverflow.com/a/10600491/711085 , votre réponse est en réalité légèrement plus courte à mettre en œuvre, à l'aide de .substring(0,3)
:
function format(n) {
with (Math) {
var base = floor(log(abs(n))/log(1000));
var suffix = 'kmb'[base-1];
return suffix ? String(n/pow(1000,base)).substring(0,3)+suffix : ''+n;
}
}
(Comme d'habitude, n'utilisez pas Math sauf si vous savez exactement ce que vous faites; attribuer var pow=...
, par exemple, causerait des bugs insensés. Voir le lien pour plus de sécurité.)
> tests = [-1001, -1, 0, 1, 2.5, 999, 1234,
1234.5, 1000001, Math.pow(10,9), Math.pow(10,12)]
> tests.forEach(function(x){ console.log(x,format(x)) })
-1001 "-1.k"
-1 "-1"
0 "0"
1 "1"
2.5 "2.5"
999 "999"
1234 "1.2k"
1234.5 "1.2k"
1000001 "1.0m"
1000000000 "1b"
1000000000000 "1000000000000"
Vous aurez besoin d'attraper le cas où le résultat est> = 1 billion, si votre exigence de 3 caractères est stricte, sinon vous risquez de créer des données corrompues, ce qui serait très mauvais.
Après quelques manipulations, cette approche semble répondre aux critères requis. S'inspire de la réponse de @ chuckator.
function abbreviateNumber(value) {
if (value <= 1000) {
return value.toString();
}
const numDigits = (""+value).length;
const suffixIndex = Math.floor(numDigits / 3);
const normalisedValue = value / Math.pow(1000, suffixIndex);
let precision = 2;
if (normalisedValue < 1) {
precision = 1;
}
const suffixes = ["", "k", "m", "b","t"];
return normalisedValue.toPrecision(precision) + suffixes[suffixIndex];
}
Intl est le «package» standard Javascript pour les comportements internationalisés implémentés. Intl.NumberFormatter est spécifiquement le formateur de nombres localisé. Donc, ce code respecte vos séparateurs de milliers et décimales configurés localement.
intlFormat(num) {
return new Intl.NumberFormat().format(Math.round(num*10)/10);
}
abbreviateNumber(value) {
let num = Math.floor(value);
if(num >= 1000000000)
return this.intlFormat(num/1000000000)+'B';
if(num >= 1000000)
return this.intlFormat(num/1000000)+'M';
if(num >= 1000)
return this.intlFormat(num/1000)+'k';
return this.intlFormat(num);
}
abbreviateNumber (999999999999) // donne 999B
Question connexe: Abrégez un nombre localisé en JavaScript pour des milliers (1k) et des millions (1m)
Beaucoup de réponses sur ce fil deviennent assez compliquées, en utilisant des objets Math
, des objets de carte, des boucles for-loop, etc. Mais ces approches n'améliorent pas vraiment la conception - elles introduisent plus de lignes de code, plus de complexité et plus de mémoire aérien. Après avoir évalué plusieurs approches, je pense que l’approche manuelle est la plus facile à comprendre et offre les meilleures performances.
const formatCash = n => {
if (n < 1e3) return n;
if (n >= 1e3 && n < 1e6) return +(n / 1e3).toFixed(1) + "K";
if (n >= 1e6 && n < 1e9) return +(n / 1e6).toFixed(1) + "M";
if (n >= 1e9 && n < 1e12) return +(n / 1e9).toFixed(1) + "B";
if (n >= 1e12) return +(n / 1e12).toFixed(1) + "T";
};
console.log(formatCash(1235000));
function converse_number (labelValue) {
// Nine Zeroes for Billions
return Math.abs(Number(labelValue)) >= 1.0e+9
? Math.abs(Number(labelValue)) / 1.0e+9 + "B"
// Six Zeroes for Millions
: Math.abs(Number(labelValue)) >= 1.0e+6
? Math.abs(Number(labelValue)) / 1.0e+6 + "M"
// Three Zeroes for Thousands
: Math.abs(Number(labelValue)) >= 1.0e+3
? Math.abs(Number(labelValue)) / 1.0e+3 + "K"
: Math.abs(Number(labelValue));
}
alert (numéro_connexion (100000000000));
J'utilise cette fonction pour obtenir ces valeurs.
function Converter(number, fraction) {
let ranges = [
{ divider: 1, suffix: '' },
{ divider: 1e3, suffix: 'K' },
{ divider: 1e6, suffix: 'M' },
{ divider: 1e9, suffix: 'G' },
{ divider: 1e12, suffix: 'T' },
{ divider: 1e15, suffix: 'P' },
{ divider: 1e18, suffix: 'E' },
]
//find index based on number of zeros
let index = (Math.abs(number).toString().length / 3).toFixed(0)
return (number / ranges[index].divider).toFixed(fraction) + ranges[index].suffix
}
Chaque 3 chiffres a un suffixe différent, c'est ce que j'essaie de trouver en premier.
Donc, supprimez le symbole négatif s'il existe , puis trouvez combien de 3 chiffres dans ce nombre.
après cela, trouvez le suffixe approprié basé sur le calcul précédent ajouté au nombre divisé.
Converter(1500, 1)
Reviendra:
1.5K
Code
const SI_PREFIXES = [
{ value: 1, symbol: '' },
{ value: 1e3, symbol: 'k' },
{ value: 1e6, symbol: 'M' },
{ value: 1e9, symbol: 'G' },
{ value: 1e12, symbol: 'T' },
{ value: 1e15, symbol: 'P' },
{ value: 1e18, symbol: 'E' },
]
const abbreviateNumber = (number) => {
if (number === 0) return number
const tier = SI_PREFIXES.filter((n) => number >= n.value).pop()
const numberFixed = (number / tier.value).toFixed(1)
return `${numberFixed}${tier.symbol}`
}
abbreviateNumber(2000) // "2.0k"
abbreviateNumber(2500) // "2.5k"
abbreviateNumber(255555555) // "255.6M"
Test:
import abbreviateNumber from './abbreviate-number'
test('abbreviateNumber', () => {
expect(abbreviateNumber(0)).toBe('0')
expect(abbreviateNumber(100)).toBe('100')
expect(abbreviateNumber(999)).toBe('999')
expect(abbreviateNumber(1000)).toBe('1.0k')
expect(abbreviateNumber(100000)).toBe('100.0k')
expect(abbreviateNumber(1000000)).toBe('1.0M')
expect(abbreviateNumber(1e6)).toBe('1.0M')
expect(abbreviateNumber(1e10)).toBe('10.0G')
expect(abbreviateNumber(1e13)).toBe('10.0T')
expect(abbreviateNumber(1e16)).toBe('10.0P')
expect(abbreviateNumber(1e19)).toBe('10.0E')
expect(abbreviateNumber(1500)).toBe('1.5k')
expect(abbreviateNumber(1555)).toBe('1.6k')
expect(abbreviateNumber(undefined)).toBe('0')
expect(abbreviateNumber(null)).toBe(null)
expect(abbreviateNumber('100')).toBe('100')
expect(abbreviateNumber('1000')).toBe('1.0k')
})
J'ai trouvé la meilleure solution sur SO ici avec des exemples d'exécution violonés car la solution @chucktator renvoie NaN dans de nombreux cas. Cela a parfaitement fonctionné pour moi.
@nimesaram
Votre solution ne sera pas souhaitable pour le cas suivant:
Input 50000
Output 50.0k
La solution suivante fonctionnera bien.
const convertNumberToShortString = (
number: number,
fraction: number
) => {
let newValue: string = number.toString();
if (number >= 1000) {
const ranges = [
{ divider: 1, suffix: '' },
{ divider: 1e3, suffix: 'k' },
{ divider: 1e6, suffix: 'm' },
{ divider: 1e9, suffix: 'b' },
{ divider: 1e12, suffix: 't' },
{ divider: 1e15, suffix: 'p' },
{ divider: 1e18, suffix: 'e' }
];
//find index based on number of zeros
const index = Math.floor(Math.abs(number).toString().length / 3);
let numString = (number / ranges[index].divider).toFixed(fraction);
numString =
parseInt(numString.substring(numString.indexOf('.') + 1)) === 0
? Math.floor(number / ranges[index].divider).toString()
: numString;
newValue = numString + ranges[index].suffix;
}
return newValue;
};
// Input 50000
// Output 50k
// Input 4500
// Output 4.5k