Saya memiliki tugas untuk mencocokkan angka floating point. Saya telah menulis ekspresi reguler berikut untuk itu:
[-+]?[0-9]*\.?[0-9]*
Tapi, itu mengembalikan kesalahan:
Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )
Sesuai pengetahuan saya, kita perlu menggunakan karakter pelarian untuk itu .
juga. Harap perbaiki saya jika saya salah.
(?:\d+(?:\.\d*)?|\.\d+)
dan telah diposting infinitum iklan di SO ...[-+]?([0-9]*[.])?[0-9]+([eE][-+]?\d+)?
jika Anda ingin menangkap notasi eksponensial juga, e, g, 3.023e-23Jawaban:
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
Ini akan cocok dengan:
123
123.456
.456
Lihat contoh kerja
Jika Anda juga ingin mencocokkan
123.
(titik tanpa bagian desimal), Anda memerlukan ekspresi yang sedikit lebih panjang: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: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: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:Dalam kasus Anda, Anda mungkin tidak lolos dari karakter garis miring terbalik dalam bahasa pemrograman Anda:
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:
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+
Cocokkan 0 atau lebih digit berurutan
Cocokkan opsional
.
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:
Sekarang kami ingin menambahkan bagian desimal, tetapi tidak sesuai dengan yang Anda pikirkan:
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:
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:Sekarang kita tinggal menambahkan tandanya:
Tentu saja, garis miring tersebut cukup mengganggu di Java, jadi kita bisa mengganti kelas karakter bentuk panjang kita:
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: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:
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, tetapiapple 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, mengembalikantrue
jika kecocokan ditemukan danfalse
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.sumber
\d+(\.\d*)?|\.\d+
/[-+]?(\d*[.])?\d+/.test("1.bc") // returns true
1.
cocok. Tambahkan^
dan$
ke awal dan akhir regex jika Anda ingin mencocokkan hanya jika seluruh masukan cocok.[-+]?(([0-9]*[.]?[0-9]+([ed][-+]?[0-9]+)?)|(inf)|(nan))
:, e / d untuk float / double presisi float. Jangan lupa bendera kasus lipat ke regexSaya tidak berpikir bahwa jawaban apa pun di halaman ini pada saat penulisan ini benar (juga banyak saran lain di tempat lain di SO juga salah). Masalahnya adalah Anda harus mencocokkan semua kemungkinan berikut:
0.35
,22.165
)0.
,1234.
).0
,.5678
)Pada saat yang sama, Anda harus memastikan bahwa setidaknya ada satu digit di suatu tempat, yaitu yang berikut ini tidak diperbolehkan:
+.
atau-.
)+
atau-
sendiriIni tampak rumit pada awalnya, tetapi salah satu cara untuk menemukan inspirasi adalah dengan melihat sumber OpenJDK untuk
java.lang.Double.valueOf(String)
metode tersebut (mulai dari http://hg.openjdk.java.net/jdk8/jdk8/jdk , klik "telusuri", arahkan ke bawah/src/share/classes/java/lang/
dan temukanDouble
kelasnya). Regex panjang yang berisi kelas ini melayani berbagai kemungkinan yang mungkin tidak ada dalam pikiran OP, tetapi mengabaikan kesederhanaan bagian-bagiannya yang berhubungan dengan NaN, tak terhingga, notasi heksadesimal dan eksponen, dan menggunakan\d
daripada notasi POSIX untuk satu digit, saya dapat mengurangi bagian penting dari regex untuk bilangan floating point bertanda tanpa eksponen ke:[+-]?((\d+\.?\d*)|(\.\d+))
Saya tidak berpikir bahwa ada cara untuk menghindari
(...)|(...)
konstruksi tanpa membiarkan sesuatu yang tidak mengandung angka, atau melarang salah satu kemungkinan yang tidak memiliki angka sebelum koma desimal atau tanpa angka setelahnya.Jelas dalam praktiknya, Anda harus memenuhi spasi kosong di belakang atau sebelumnya, baik di regex itu sendiri atau dalam kode yang menggunakannya.
sumber
123.
, maka ya ... sakelar atau adalah satu-satunya solusi, seperti yang saya tunjukkan dalam komentar di posting asli saya.[+-]?((?=\.?\d)\d*\.?\d*)
digunakan untuk menghindari pergantian? Ini menggunakan lookahead ...yang Anda butuhkan adalah:
Saya lolos dari tanda "+" dan "-" dan juga mengelompokkan desimal dengan angka berikut karena sesuatu seperti "1." bukan angka yang valid.
Perubahan akan memungkinkan Anda untuk mencocokkan bilangan bulat dan float. sebagai contoh:
sumber
.1
itu tidak diizinkan, meskipun masukan seperti itu secara universal diakui sebagai benar.-
dan+
, yang bukan angka. Regex itu rumit! :)\.
tidak berhasil.Saya ingin mencocokkan apa yang dianggap kebanyakan bahasa sebagai angka yang valid (integer dan float):
'5' / '-5'
'1.0' / '1.' / '.1' / '-1.' / '-.1'
'0.45326e+04', '666999e-05', '0.2e-3', '-33.e-1'
Catatan:
preceding sign of number ('-' or '+') is optional
'-1.' and '-.1' are valid but '.' and '-.' are invalid
'.1e3' is valid, but '.e3' and 'e3' are invalid
Untuk mendukung '1'. dan '.1' kita membutuhkan operator OR ('|') untuk memastikan kita mengecualikan '.' dari pencocokan.
[+-]?
+/- sing adalah opsional karena?
berarti 0 atau 1 pertandingan(
karena kita memiliki 2 sub ekspresi kita perlu meletakkannya di dalam tanda kurung\d+([.]\d*)?(e[+-]?\d+)?
Ini untuk angka yang dimulai dengan digit|
memisahkan sub ekspresi[.]\d+(e[+-]?\d+)?
ini untuk angka yang dimulai dengan '.')
akhir ekspresi[.]
karakter pertama adalah titik (di dalam tanda kurung atau yang lain adalah karakter wildcard)\d+
satu atau lebih digit(e[+-]?\d+)?
ini adalah notasi ilmiah opsional (0 atau 1 cocok karena diakhiri dengan '?')\d+
satu atau lebih digit([.]\d*)?
opsional kita dapat memiliki karakter titik nol atau lebih digit setelahnya(e[+-]?\d+)?
ini adalah notasi ilmiah opsionale
literal yang menentukan eksponen[+-]?
tanda eksponen opsional\d+
satu atau lebih digitSemua itu digabungkan:
Untuk menerima
E
juga:( Kasus uji )
sumber
Ini adalah sederhana: Anda telah menggunakan Java dan Anda harus menggunakan
\\.
bukan\.
(mencari karakter melarikan diri di Jawa).sumber
Yang ini berhasil untuk saya:
Anda juga dapat menggunakan yang ini (tanpa parameter bernama):
Gunakan beberapa penguji regex online untuk mengujinya (mis. Regex101)
sumber
Ini akan cocok dengan:
sumber
[+-]?
- tanda pengantar opsional(([1-9][0-9]*)|(0))
- bilangan bulat tanpa nol di depan, termasuk nol tunggal([.,][0-9]+)?
- bagian pecahan opsionalsumber
Di C ++ menggunakan perpustakaan regex
Jawabannya akan seperti ini:
Perhatikan bahwa saya tidak mengambil simbol tanda, jika Anda menginginkannya dengan simbol tanda itu akan menjadi seperti ini:
Ini juga memisahkan angka biasa atau angka desimal.
sumber
Dalam notasi c, bilangan float dapat muncul dalam bentuk berikut:
Untuk membuat ekspresi reguler float, pertama-tama saya akan membuat "variabel ekspresi reguler int":
Sekarang, saya akan menulis potongan kecil ekspresi reguler float - solusinya adalah menggabungkan potongan tersebut dengan atau simbol "|".
Potongan:
Solusi akhir (menggabungkan potongan kecil):
sumber
Coba solusi ini.
sumber
untuk javascript
Yang akan berhasil untuk 1,23 1234.22 0 0,12 12
Anda dapat mengubah bagian dalam
{}
untuk mendapatkan hasil yang berbeda dalam panjang desimal dan juga bagian depan desimal. Ini digunakan dalam masukan untuk memasukkan angka dan memeriksa setiap masukan saat Anda mengetik hanya mengizinkan yang lewat.sumber