TL; DR
Gunakan [.]
alih-alih \.
dan [0-9]
alih-alih \d
untuk menghindari keluar dari masalah dalam beberapa bahasa (seperti Java).
Terima kasih kepada yang tak bernama karena awalnya mengenali ini.
Salah satu pola yang relatif sederhana untuk mencocokkan bilangan floating point adalah
[+-]?([0-9]*[.])?[0-9]+
Ini akan cocok dengan:
Lihat contoh kerja
Jika Anda juga ingin mencocokkan 123.
(titik tanpa bagian desimal), Anda memerlukan ekspresi yang sedikit lebih panjang:
[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)
Lihat jawaban pkeller untuk penjelasan lebih lengkap tentang pola ini
Jika Anda ingin memasukkan angka non-desimal, seperti heksadesimal dan oktal, lihat jawaban saya untuk Bagaimana cara mengidentifikasi jika string adalah angka? .
Jika Anda ingin memvalidasi bahwa input adalah angka (daripada mencari angka dalam input), maka Anda harus mengapit pola dengan ^
dan $
, seperti:
^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$
Ekspresi Reguler Tidak Beraturan
"Ekspresi reguler", seperti yang diterapkan di sebagian besar bahasa modern, API, kerangka kerja, perpustakaan, dll., Didasarkan pada konsep yang dikembangkan dalam teori bahasa formal . Namun, insinyur perangkat lunak telah menambahkan banyak ekstensi yang membawa implementasi ini jauh melampaui definisi formal. Jadi, meskipun sebagian besar mesin ekspresi reguler mirip satu sama lain, sebenarnya tidak ada standar. Untuk alasan ini, banyak hal bergantung pada bahasa, API, framework, atau library apa yang Anda gunakan.
(Kebetulan, untuk membantu mengurangi kebingungan, banyak yang menggunakan " regex " atau " regexp " untuk mendeskripsikan bahasa pencocokan yang disempurnakan ini. Lihat Apakah Regex Sama dengan Ekspresi Reguler? Di RexEgg.com untuk informasi selengkapnya.)
Meskipun demikian, sebagian besar mesin regex (sebenarnya, semuanya, sejauh yang saya tahu) akan menerimanya \.
. Kemungkinan besar, ada masalah saat kabur.
Masalah dengan Melarikan Diri
Beberapa bahasa memiliki dukungan bawaan untuk ekspresi reguler, seperti JavaScript . Untuk bahasa yang tidak, pelolosan bisa menjadi masalah.
Ini karena Anda pada dasarnya membuat kode dalam bahasa dalam suatu bahasa. Java, misalnya, menggunakan \
karakter escape dalam stringnya, jadi jika Anda ingin menempatkan karakter backslash literal dalam string, Anda harus menghindarinya:
// creates a single character string: "\"
String x = "\\";
Namun, ekspresi reguler juga menggunakan \
karakter untuk melarikan diri, jadi jika Anda ingin mencocokkan \
karakter literal , Anda harus melepaskannya untuk mesin regexe, lalu melepaskannya lagi untuk Java:
// Creates a two-character string: "\\"
// When used as a regex pattern, will match a single character: "\"
String regexPattern = "\\\\";
Dalam kasus Anda, Anda mungkin tidak lolos dari karakter garis miring terbalik dalam bahasa pemrograman Anda:
// will most likely result in an "Illegal escape character" error
String wrongPattern = "\.";
// will result in the string "\."
String correctPattern = "\\.";
Semua pelarian ini bisa sangat membingungkan. Jika bahasa yang Anda gunakan mendukung string mentah , Anda harus menggunakannya untuk mengurangi jumlah garis miring terbalik, tetapi tidak semua bahasa mendukung string mentah (terutama: Java). Untungnya, ada alternatif yang akan berhasil beberapa saat:
String correctPattern = "[.]";
Untuk mesin regex, \.
dan [.]
artinya sama persis. Perhatikan bahwa ini tidak berfungsi di setiap kasus, seperti newline ( \\n
), open square bracket ( \\[
) dan backslash ( \\\\
atau [\\]
).
Catatan tentang Nomor Pencocokan
(Petunjuk: Ini lebih sulit dari yang Anda pikirkan)
Mencocokkan angka adalah salah satu hal yang menurut Anda cukup mudah dengan regex, tetapi sebenarnya cukup rumit. Mari kita lihat pendekatan Anda, sepotong demi sepotong:
[-+]?
Cocok dengan opsional -
atau+
[0-9]*
Cocokkan 0 atau lebih digit berurutan
\.?
Cocokkan opsional .
[0-9]*
Cocokkan 0 atau lebih digit berurutan
Pertama, kita bisa sedikit membersihkan ekspresi ini dengan menggunakan singkatan kelas karakter untuk digit (perhatikan bahwa ini juga rentan terhadap masalah pelarian yang disebutkan di atas):
[0-9]
= \d
Saya akan menggunakan di \d
bawah, tetapi perlu diingat bahwa artinya sama dengan [0-9]
. (Sebenarnya, di beberapa mesin \d
akan mencocokkan angka dari semua skrip, jadi itu akan cocok lebih dari yang [0-9]
akan, tapi itu mungkin tidak signifikan dalam kasus Anda.)
Sekarang, jika Anda melihat ini dengan cermat, Anda akan menyadari bahwa setiap bagian dari pola Anda adalah opsional . Pola ini bisa cocok dengan string panjang 0; string hanya terdiri dari +
atau -
; atau, string yang hanya terdiri dari a .
. Ini mungkin bukan yang Anda inginkan.
Untuk memperbaikinya, sebaiknya mulai dengan "menambatkan" ekspresi reguler Anda dengan string minimal yang diperlukan, mungkin satu digit:
\d+
Sekarang kami ingin menambahkan bagian desimal, tetapi tidak sesuai dengan yang Anda pikirkan:
\d+\.?\d* /* This isn't quite correct. */
Ini akan tetap cocok dengan nilai seperti 123.
. Lebih buruk lagi, ada sedikit kejahatan tentang itu. Titik ini opsional, artinya Anda memiliki dua kelas berulang berdampingan ( \d+
dan \d*
). Ini sebenarnya bisa berbahaya jika digunakan dengan cara yang salah, membuka sistem Anda terhadap serangan DoS.
Untuk memperbaikinya, daripada memperlakukan titik sebagai opsional, kita perlu memperlakukannya sebagai diperlukan (untuk memisahkan kelas karakter yang berulang) dan sebaliknya menjadikan seluruh bagian desimal opsional:
\d+(\.\d+)? /* Better. But... */
Ini terlihat lebih baik sekarang. Kami memerlukan titik antara urutan pertama dan detik, tetapi ada kesalahan fatal: kami tidak bisa mencocokkan .123
karena sekarang diperlukan digit terdepan.
Ini sebenarnya cukup mudah untuk diperbaiki. Alih-alih menjadikan bagian "desimal" dari angka tersebut opsional, kita perlu melihatnya sebagai urutan karakter: 1 atau lebih angka yang dapat diawali dengan .
yang dapat diawali dengan 0 atau lebih angka:
(\d*\.)?\d+
Sekarang kita tinggal menambahkan tandanya:
[+-]?(\d*\.)?\d+
Tentu saja, garis miring tersebut cukup mengganggu di Java, jadi kita bisa mengganti kelas karakter bentuk panjang kita:
[+-]?([0-9]*[.])?[0-9]+
Mencocokkan versus Memvalidasi
Ini telah muncul di komentar beberapa kali, jadi saya menambahkan tambahan tentang pencocokan versus memvalidasi.
Tujuan pencocokan adalah untuk menemukan beberapa konten di dalam masukan ("jarum di tumpukan jerami"). Tujuan dari validasi adalah untuk memastikan bahwa masukan dalam format yang diharapkan.
Regexes, menurut sifatnya, hanya cocok dengan teks. Dengan beberapa masukan, mereka akan menemukan beberapa teks yang cocok atau tidak. Namun, dengan "menjepret" ekspresi ke awal dan akhir input dengan tag anchor ( ^
dan $
), kita dapat memastikan bahwa tidak ada kecocokan yang ditemukan kecuali seluruh input cocok dengan ekspresi tersebut, secara efektif menggunakan regex untuk memvalidasi .
Regex yang dijelaskan di atas ( [+-]?([0-9]*[.])?[0-9]+
) akan cocok dengan satu atau beberapa angka dalam string target. Jadi diberi masukan:
apple 1.34 pear 7.98 version 1.2.3.4
Regex akan cocok 1.34
, 7.98
, 1.2
, .3
dan .4
.
Untuk memvalidasi bahwa masukan yang diberikan adalah angka dan tidak lain adalah angka, "pasang" ekspresi ke awal dan akhir masukan dengan membungkusnya dalam tag jangkar:
^[+-]?([0-9]*[.])?[0-9]+$
Ini hanya akan menemukan kecocokan jika seluruh masukan adalah bilangan titik mengambang, dan tidak akan menemukan kecocokan jika masukan berisi karakter tambahan. Jadi, jika diberi masukan 1.2
, kecocokan akan ditemukan, tetapi apple 1.2 pear
tidak ada kecocokan yang akan ditemukan.
Perhatikan bahwa beberapa mesin regex memiliki validate
, isMatch
atau fungsi serupa, yang pada dasarnya melakukan apa yang telah saya jelaskan secara otomatis, mengembalikan true
jika kecocokan ditemukan dan false
jika tidak ada kecocokan yang ditemukan. Juga perlu diingat bahwa beberapa mesin memungkinkan Anda untuk mengatur flag yang mengubah definisi ^
dan $
, mencocokkan awal / akhir baris, bukan awal / akhir dari seluruh input. Ini biasanya bukan default, tetapi waspadalah terhadap flag-flag ini.