Bagaimana cara mengurai string dengan pemisah koma seribu ke angka?

104

Saya memiliki 2,299.00sebagai string dan saya mencoba menguraikannya menjadi angka. Saya mencoba menggunakan parseFloat, yang menghasilkan 2. Sepertinya masalahnya adalah koma, tetapi bagaimana saya akan menyelesaikan masalah ini dengan cara yang benar? Hapus saja koma?

var x = parseFloat("2,299.00")
alert(x);

pengguna1540714
sumber

Jawaban:

121

Ya hapus koma:

parseFloat(yournumber.replace(/,/g, ''));
Sam
sumber
7
Ya, tapi sekarang tempat desimalnya hilang. 2300.00 menghasilkan 2300 misalnya.
pengguna1540714
@ user1540714 itu karena itu float daripada string. Jika Anda kemudian perlu mengeluarkannya, Anda perlu memformatnya agar selalu menampilkan 2 titik desimal.
Jon Taylor
Bisakah itu dihindari? Saya akan mencoba untukTetap
pengguna1540714
38
Bolehkah saya menyarankan agar kami menangkap semua koma dengan menggunakan: .replace(/,/g, '') Regex ini menggunakan global guntuk mengganti-semua.
gdibble
32
Saya tidak tahu mengapa jawaban ini mendapat begitu banyak suara positif dan dipilih sebagai benar, ini memiliki dua masalah serius. 1. Ia tidak dapat menangani angka dengan banyak koma, misalnya parseFloat("2,000,000.00".replace(',',''))kembali 2000dan 2. gagal di banyak wilayah di dunia di mana ,tempat desimal, misalnya parseFloat("2.000.000,00".replace(',',''))kembali 2- lihat jawaban saya di bawah untuk sesuatu yang berfungsi di mana-mana di dunia.
David Meister
113

Menghapus koma berpotensi berbahaya karena, seperti yang disebutkan orang lain di komentar, banyak lokal menggunakan koma untuk mengartikan sesuatu yang berbeda (seperti tempat desimal).

Saya tidak tahu dari mana Anda mendapatkan string Anda, tetapi di beberapa tempat di dunia "2,299.00"=2.299

The Intlobjek bisa menjadi cara yang baik untuk mengatasi masalah ini, tapi entah bagaimana mereka berhasil kapal spec dengan hanya Intl.NumberFormat.format()API dan tidak ada parserekan :(

Satu-satunya cara untuk mengurai string dengan karakter numerik budaya di dalamnya menjadi nomor yang dapat dikenali mesin dengan cara apa pun yang i18n waras adalah dengan menggunakan pustaka yang memanfaatkan data CLDR untuk menutupi semua kemungkinan cara memformat string angka http: //cldr.unicode. org /

Dua opsi JS terbaik yang pernah saya temui sejauh ini:

David Meister
sumber
4
Tidak bisa percaya belum ada yang memberi suara positif pada jawaban ini, ini satu-satunya jawaban yang sebenarnya di halaman ini!
evilkos
9
Sangat setuju bahwa Intl seharusnya memiliki mitra penguraian. Tampak jelas bahwa orang akan membutuhkan ini.
carlossless
Ini adalah satu-satunya cara sistematis untuk melakukan ini. Tidak dapat mencapai ini dengan satu pendekatan cocok untuk semua regex. Koma dan titik memiliki arti yang berbeda dalam bahasa yang berbeda.
Wildhammer
38

Pada browser modern, Anda dapat menggunakan Intl.NumberFormat bawaan untuk mendeteksi format angka browser dan menormalkan masukan agar cocok.

function parseNumber(value, locale = navigator.language) {
  const example = Intl.NumberFormat(locale).format('1.1');
  const cleanPattern = new RegExp(`[^-+0-9${ example.charAt( 1 ) }]`, 'g');
  const cleaned = value.replace(cleanPattern, '');
  const normalized = cleaned.replace(example.charAt(1), '.');

  return parseFloat(normalized);
}

const corpus = {
  '1.123': {
    expected: 1.123,
    locale: 'en-US'
  },
  '1,123': {
    expected: 1123,
    locale: 'en-US'
  },
  '2.123': {
    expected: 2123,
    locale: 'fr-FR'
  },
  '2,123': {
    expected: 2.123,
    locale: 'fr-FR'
  },
}


for (const candidate in corpus) {
  const {
    locale,
    expected
  } = corpus[candidate];
  const parsed = parseNumber(candidate, locale);

  console.log(`${ candidate } in ${ corpus[ candidate ].locale } == ${ expected }? ${ parsed === expected }`);
}

Ruang mereka jelas untuk beberapa pengoptimalan dan penyimpanan dalam cache tetapi ini berfungsi dengan andal di semua bahasa.

Paul Alexander
sumber
Mengapa ini tidak mendapat banyak suara positif !!! Ini adalah solusi paling elegan untuk INPUT dalam format internasional! Terima kasih!!
kpollock
dalam mata uang Prancis adalah 231 123 413,12
stackdave
26

Hapus apa pun yang bukan angka, koma desimal, atau tanda minus ( -):

var str = "2,299.00";
str = str.replace(/[^\d\.\-]/g, ""); // You might also include + if you want them to be able to type it
var num = parseFloat(str);

Biola diperbarui

Perhatikan bahwa ini tidak akan berfungsi untuk angka dalam notasi ilmiah. Jika Anda ingin, mengubah replacejalur untuk menambahkan e, E, dan +untuk daftar karakter yang dapat diterima:

str = str.replace(/[^\d\.\-eE+]/g, "");
TJ Crowder
sumber
4
Ini tidak akan berhasil untuk bilangan negatif atau bilangan dalam notasi ilmiah.
Aadit M Shah
1
str = str.replace(/(\d+),(?=\d{3}(\D|$))/g, "$1"); Inilah yang akan saya gunakan tetapi saya sama sekali tidak berguna di regex dan merupakan sesuatu yang saya temukan beberapa waktu lalu di beberapa utas SO lainnya.
Jon Taylor
@JonTaylor: Tujuannya di sini bukan untuk memvalidasi nomor, hanya untuk membuatnya berfungsi parseFloat- yang akan memvalidasinya. :-)
TJ Crowder
yang saya lakukan, sejauh yang saya tahu. Saya menggunakan ini untuk mengubah 1,234,567 dll menjadi 1234567. Seperti yang saya katakan meskipun saya sama sekali tidak berguna di regex jadi saya tidak bisa seumur hidup saya memberi tahu Anda apa yang sebenarnya dilakukannya lol.
Jon Taylor
1
Ide buruk untuk menghapus "-" tanda minus - dapatkan nomor lain secara lengkap, dan juga jika Anda mengurai format yang beragam, "7.500"! == "7.500"
Serge
14

Biasanya Anda harus mempertimbangkan untuk menggunakan kolom input yang tidak mengizinkan input teks gratis untuk nilai numerik. Tetapi mungkin ada kasus, ketika Anda perlu menebak format input. Misalnya 1,234,56 di Jerman berarti 1,234,56 di AS. Lihat https://salesforce.stackexchange.com/a/21404 untuk daftar negara yang menggunakan koma sebagai desimal.

Saya menggunakan fungsi berikut untuk melakukan tebakan terbaik dan menghapus semua karakter non-numerik:

function parseNumber(strg) {
    var strg = strg || "";
    var decimal = '.';
    strg = strg.replace(/[^0-9$.,]/g, '');
    if(strg.indexOf(',') > strg.indexOf('.')) decimal = ',';
    if((strg.match(new RegExp("\\" + decimal,"g")) || []).length > 1) decimal="";
    if (decimal != "" && (strg.length - strg.indexOf(decimal) - 1 == 3) && strg.indexOf("0" + decimal)!==0) decimal = "";
    strg = strg.replace(new RegExp("[^0-9$" + decimal + "]","g"), "");
    strg = strg.replace(',', '.');
    return parseFloat(strg);
}   

Coba di sini: https://plnkr.co/edit/9p5Y6H?p=preview

Contoh:

1.234,56  => 1234.56
1,234.56USD => 1234.56
1,234,567 => 1234567
1.234.567 => 1234567
1,234.567 => 1234.567
1.234 => 1234 // might be wrong - best guess
1,234 => 1234 // might be wrong - best guess
1.2345 => 1.2345
0,123 => 0.123

Fungsi ini memiliki satu titik lemah: Tidak mungkin menebak format jika Anda memiliki 1.123 atau 1.123 - karena bergantung pada format lokal, keduanya mungkin berupa koma atau pemisah ribuan. Dalam kasus khusus ini, fungsi akan memperlakukan pemisah sebagai pemisah ribuan dan mengembalikan 1123.

Gerfried
sumber
Gagal untuk angka seperti 1,111.11, yang jelas merupakan format bahasa Inggris, tetapi mengembalikan 111111
Tn. Goferito
Terima kasih, Pak Goferito - maaf - saya telah memperbaiki fungsinya.
Gerfried
Sepertinya ini juga mungkin gagal untuk angka yang sangat kecil "0,124" dalam bahasa Prancis misalnya.
Paul Alexander
Wou, bagus! Ini hampir persis, apa yang saya cari: 3,00 €juga diganti menjadi 3,00. Sekadar catatan, yang 3,001diformat menjadi 3001. Untuk menghindari ini, masukan harus selalu dengan simbol desimal. Misalnya 3,001.00€ 3,001.00mengkonversi dengan benar. Juga, tolong, perbarui jsfiddle. 0,124masih ada yang diubah menjadi 124
Arnis Juraga
Selamat sobat saya pikir itu layak untuk menjadi jawaban yang benar
Waheed
5

Mengherankan bahwa mereka menyertakan toLocaleString tetapi bukan metode parse . Setidaknya toLocaleString tanpa argumen didukung dengan baik di IE6 +.

Untuk solusi i18n , saya datang dengan ini:

Pertama, deteksi pemisah desimal lokal pengguna:

var decimalSeparator = 1.1;
decimalSeparator = decimalSeparator.toLocaleString().substring(1, 2);

Kemudian normalkan angkanya jika ada lebih dari satu pemisah desimal dalam String:

var pattern = "([" + decimalSeparator + "])(?=.*\\1)";separator
var formatted = valor.replace(new RegExp(pattern, "g"), "");

Terakhir, hapus apa pun yang bukan angka atau pemisah desimal:

formatted = formatted.replace(new RegExp("[^0-9" + decimalSeparator + "]", "g"), '');
return Number(formatted.replace(decimalSeparator, "."));
Fábio
sumber
5

Ini adalah pembungkus sederhana yang tidak mengganggu di sekitar parseFloatfungsi.

function parseLocaleNumber(str) {
  // Detect the user's locale decimal separator:
  var decimalSeparator = (1.1).toLocaleString().substring(1, 2);
  // Detect the user's locale thousand separator:
  var thousandSeparator = (1000).toLocaleString().substring(1, 2);
  // In case there are locales that don't use a thousand separator
  if (thousandSeparator.match(/\d/))
    thousandSeparator = '';

  str = str
    .replace(new RegExp(thousandSeparator, 'g'), '')
    .replace(new RegExp(decimalSeparator), '.')

  return parseFloat(str);
}
Adam Jagosz
sumber
2

Jika Anda ingin menghindari masalah yang diposting oleh David Meister dan Anda yakin tentang jumlah tempat desimalnya, Anda dapat mengganti semua titik dan koma dan membaginya dengan 100, mis .:

var value = "2,299.00";
var amount = parseFloat(value.replace(/"|\,|\./g, ''))/100;

atau jika Anda memiliki 3 desimal

var value = "2,299.001";
var amount = parseFloat(value.replace(/"|\,|\./g, ''))/1000;

Terserah Anda jika ingin menggunakan parseInt, parseFloat atau Number. Juga Jika Anda ingin mempertahankan jumlah tempat desimal Anda dapat menggunakan fungsi .toFixed (...).

Fernando Limeira
sumber
1

Semua jawaban ini gagal jika Anda memiliki angka dalam jutaan.

3.456.789 hanya akan mengembalikan 3456 dengan metode replace.

Jawaban paling benar hanya dengan menghilangkan koma adalah.

var number = '3,456,789.12';
number.split(',').join('');
/* number now equips 3456789.12 */
parseFloat(number);

Atau hanya ditulis.

number = parseFloat(number.split(',').join(''));
Kasus
sumber
Tentu saja, orang Amerika menggunakan koma dan bukan titik. Akan sangat bodoh untuk mencoba membuat monster mencoba menangani keduanya.
Kasus
2
tetapi "monstrositas" seperti itu sudah ada sebagai bagian dari apa yang disediakan Unicode (lihat jawaban saya). Saya yakin Anda tidak akan merasa terlalu bodoh tentang hal ini jika Anda menjalankan perusahaan dengan pelanggan internasional.
David Meister
1

Ini mengubah angka di tempat apa pun menjadi angka normal. Berfungsi untuk poin desimal juga:

function numberFromLocaleString(stringValue, locale){
    var parts = Number(1111.11).toLocaleString(locale).replace(/\d+/g,'').split('');
    if (stringValue === null)
        return null;
    if (parts.length==1) {
        parts.unshift('');
    }   
    return Number(String(stringValue).replace(new RegExp(parts[0].replace(/\s/g,' '),'g'), '').replace(parts[1],"."));
}
//Use default browser locale
numberFromLocaleString("1,223,333.567") //1223333.567

//Use specific locale
numberFromLocaleString("1 223 333,567", "ru") //1223333.567
Eldar Gerfanov
sumber
1

Dengan fungsi ini Anda akan dapat memformat nilai dalam berbagai format seperti 1.234,56dan 1,234.56, dan bahkan dengan kesalahan seperti 1.234.56dan1,234,56

/**
 * @param {string} value: value to convert
 * @param {bool} coerce: force float return or NaN
 */
function parseFloatFromString(value, coerce) {
    value = String(value).trim();

    if ('' === value) {
        return value;
    }

    // check if the string can be converted to float as-is
    var parsed = parseFloat(value);
    if (String(parsed) === value) {
        return fixDecimals(parsed, 2);
    }

    // replace arabic numbers by latin
    value = value
    // arabic
    .replace(/[\u0660-\u0669]/g, function(d) {
        return d.charCodeAt(0) - 1632;
    })

    // persian
    .replace(/[\u06F0-\u06F9]/g, function(d) {
        return d.charCodeAt(0) - 1776;
    });

    // remove all non-digit characters
    var split = value.split(/[^\dE-]+/);

    if (1 === split.length) {
        // there's no decimal part
        return fixDecimals(parseFloat(value), 2);
    }

    for (var i = 0; i < split.length; i++) {
        if ('' === split[i]) {
            return coerce ? fixDecimals(parseFloat(0), 2) : NaN;
        }
    }

    // use the last part as decimal
    var decimal = split.pop();

    // reconstruct the number using dot as decimal separator
    return fixDecimals(parseFloat(split.join('') +  '.' + decimal), 2);
}

function fixDecimals(num, precision) {
    return (Math.floor(num * 100) / 100).toFixed(precision);
}
parseFloatFromString('1.234,56')
"1234.56"
parseFloatFromString('1,234.56')
"1234.56"
parseFloatFromString('1.234.56')
"1234.56"
parseFloatFromString('1,234,56')
"1234.56"
joseantgv
sumber
0

Jika Anda menginginkan jawaban l10n lakukan dengan cara ini. Contoh menggunakan mata uang, tetapi Anda tidak membutuhkannya. Library Intl perlu di-polyfill jika Anda harus mendukung browser lama.

var value = "2,299.00";
var currencyId = "USD";
var nf = new Intl.NumberFormat(undefined, {style:'currency', currency: currencyId, minimumFractionDigits: 2});

value = nf.format(value.replace(/,/g, ""));
Tony Topper
sumber
9
ini sebenarnya bukan jawaban l10n, karena untuk beberapa lokal (misalnya DE) koma adalah koma desimal.
Andreas
Dan juga replace()hanya menggantikan pertandingan pertama saat tidak digunakan RegExpdengan 'g'bendera.
binki
@binki Terima kasih. Tetap.
Tony Topper
@Andreas Ini adalah jawaban l10n. Jika Anda menginginkan mata uang lain, Anda cukup mengubah nilai currencyId ke currencyId negara tersebut.
Tony Topper
1
@TonyTopper ini tidak mengubah fakta bahwa penggantian pemisah ribuan di-hardcode ,yang ada dalam pemisah koma di beberapa lokal
Andreas
0

Ganti koma dengan string kosong:

var x = parseFloat("2,299.00".replace(",",""))
alert(x);

Aadit M Shah
sumber
ini tidak aman. Seperti disebutkan di jawaban lain, di banyak bagian dunia koma mewakili titik desimal.
David Meister
1
Juga metode ini tidak akan bekerja pada 2.299.000,00 karena hanya akan menggantikan koma pertama
wizulus
0

Jika Anda memiliki sekumpulan kecil lokal untuk mendukung Anda mungkin akan lebih baik dengan hanya melakukan hardcode beberapa aturan sederhana:

function parseNumber(str, locale) {
  let radix = ',';
  if (locale.match(/(en|th)([-_].+)?/)) {
    radix = '.';
  }
  return Number(str
    .replace(new RegExp('[^\\d\\' + radix + ']', 'g'), '')
    .replace(radix, '.'));
}
Andreas Baumgart
sumber
0
const parseLocaleNumber = strNum => {
    const decSep = (1.1).toLocaleString().substring(1, 2);
    const formatted = strNum
        .replace(new RegExp(`([${decSep}])(?=.*\\1)`, 'g'), '')
        .replace(new RegExp(`[^0-9${decSep}]`, 'g'), '');
    return Number(formatted.replace(decSep, '.'));
};
Denys Rusov
sumber
0
Number("2,299.00".split(',').join(''));   // 2299

Fungsi pemisahan membagi string menjadi larik menggunakan "," sebagai pemisah dan mengembalikan larik.
Fungsi gabungan menggabungkan elemen-elemen larik yang dikembalikan dari fungsi pemisahan.
Fungsi Number () mengubah string yang digabungkan menjadi angka.

Bruno
sumber
Tolong uraikan lebih banyak tentang apa solusinya dan bagaimana cara memecahkan masalah.
Tariq