Mencari UUID dalam teks dengan regex

224

Saya mencari UUID dalam blok teks menggunakan regex. Saat ini saya mengandalkan asumsi bahwa semua UUID akan mengikuti pola 8-4-4-4-12 digit heksadesimal.

Adakah yang bisa memikirkan kasus penggunaan di mana asumsi ini tidak valid dan akan menyebabkan saya kehilangan beberapa UUID?

Orang
sumber
Pertanyaan ini sejak 6 tahun lalu adalah untuk membantu saya dalam proyek menemukan kartu kredit dalam satu blok teks. Saya kemudian membuka kode sumber yang terhubung dari posting blog saya yang menjelaskan nuansa yang disebabkan oleh UUID ketika mencari kartu kredit guyellisrocks.com/2013/11/…
Guy
4
Pencarian untuk pencocokan pola ekspresi reguler UUID membawa saya ke pos stack overflow ini tetapi jawaban yang diterima sebenarnya bukan jawaban. Selain itu, tautan yang Anda berikan dalam komentar di bawah pertanyaan Anda juga tidak memiliki polanya (kecuali saya melewatkan sesuatu). Apakah salah satu dari jawaban ini adalah sesuatu yang akhirnya Anda gunakan?
Tass
Jika Anda mengikuti kelinci warren tautan dimulai dengan yang saya posting Anda mungkin menemukan baris ini di GitHub yang memiliki regex yang akhirnya saya gunakan. (Dapat dimengerti bahwa ini sulit ditemukan.) Kode dan file itu dapat membantu Anda: github.com/guyellis/CreditCard/blob/master/Company.CreditCard/…
Guy
1
Tak satu pun dari jawaban ini tampaknya memberikan regex tunggal untuk semua varian hanya RID 4122 UUIDs. Tapi sepertinya jawaban seperti itu diberikan di sini: stackoverflow.com/a/13653180/421049
Garret Wilson

Jawaban:

41

Saya setuju bahwa menurut definisi regex Anda tidak ketinggalan UUID apa pun. Namun mungkin berguna untuk mencatat bahwa jika Anda mencari terutama untuk Pengidentifikasi Unik Global Microsoft (GUID), ada lima representasi string yang setara untuk GUID:

"ca761232ed4211cebacd00aa0057b223" 

"CA761232-ED42-11CE-BACD-00AA0057B223" 

"{CA761232-ED42-11CE-BACD-00AA0057B223}" 

"(CA761232-ED42-11CE-BACD-00AA0057B223)" 

"{0xCA761232, 0xED42, 0x11CE, {0xBA, 0xCD, 0x00, 0xAA, 0x00, 0x57, 0xB2, 0x23}}" 
Panos
sumber
3
Di bawah situasi apa pola pertama akan ditemukan? yaitu apakah ada fungsi .Net yang akan menghapus tanda hubung atau mengembalikan GUID tanpa tanda hubung?
Guy
1
Anda bisa mendapatkannya dengan myGuid.ToString ("N").
Panos
462

Regex untuk uuid adalah:

\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b
Ivelin
sumber
19
buat itu [a-f0-9]! Karena hex! Regex Anda (sebagaimana adanya) dapat mengembalikan positif palsu.
exhuma
13
Dalam beberapa kasus Anda bahkan mungkin ingin membuatnya [a-fA-F0-9] atau [A-F0-9].
Hans-Peter Störr
22
@ cyber-monk: [0-9a-f] identik dengan [a-f0-9] dan [0123456789abcdef] dalam arti dan kecepatan, karena regex diubah menjadi mesin negara, dengan masing-masing digit hex diubah menjadi entri dalam tabel-negara. Untuk titik masuk ke bagaimana ini bekerja, lihat en.wikipedia.org/wiki/Nondeterministic_finite_automaton
JesperSM
10
Solusi ini tidak sepenuhnya benar. Ini cocok dengan ID yang memiliki versi dan karakter varian tidak valid per RFC4122. Solusi @Gajus lebih tepat dalam hal itu. Selain itu, RFC memungkinkan karakter huruf besar pada input, sehingga menambahkan [AF] akan sesuai.
broofa
4
@broofa, saya melihat bahwa Anda benar-benar ditetapkan pada semua orang yang hanya cocok dengan UUID yang konsisten dengan RFC. Namun, saya pikir fakta bahwa Anda harus menunjukkan ini berkali-kali adalah indikator yang kuat bahwa tidak semua UUID akan menggunakan versi RFC dan indikator varian. Definisi UUID en.wikipedia.org/wiki/Uuid#Definition menyatakan pola 8-4-4-4-12 sederhana dan 2 ^ 128 kemungkinan. RFC hanya mewakili sebagian saja. Jadi apa yang ingin Anda cocokkan? Subset, atau semuanya?
Bruno Bronosky
120

@ ivelin: UUID dapat memiliki modal. Jadi Anda harus toLowerCase () string atau menggunakan:

[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}

Akan hanya berkomentar ini tetapi tidak cukup rep :)

Matthew F. Robben
sumber
22
Biasanya Anda dapat menangani ini dengan mendefinisikan pola sebagai case-sensitive dengan i setelah pola, ini membuat pola yang lebih bersih: / [0-9a-f] {8} - [0-9a-f] {4} - [0 -9a-f] {4} - [0-9a-f] {4} - [0-9a-f] {12} / i
Thomas Bindzus
@ThomasBindzus Opsi itu tidak tersedia dalam semua bahasa. Pola asli dalam jawaban ini bekerja untuk saya di Go. The /.../iVersi tidak.
Chris Redford
110

Versi 4 UUID memiliki bentuk xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx di mana x adalah digit heksadesimal dan y adalah salah satu dari 8, 9, A, atau B. misalnya f47ac10b-58cc-4372-a567-0e02b2c3d479.

sumber: http://en.wikipedia.org/wiki/Uuid#Definition

Oleh karena itu, ini secara teknis lebih benar:

/[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/
Gajus
sumber
Saya tidak berpikir Anda maksud az.
Bruno Bronosky
8
Perlu menerima [AF] juga. Per bagian 3 dari RFC4122: 'Nilai heksadesimal "a" hingga "f" dihasilkan sebagai karakter huruf kecil dan tidak sensitif huruf pada input '. Juga (:?8|9|A|B)mungkin sedikit lebih mudah dibaca[89aAbB]
broofa
1
Perlu menyalin modifikasi @ broofa; karena milik Anda tidak termasuk huruf kecil A atau B.
DAPAT DILARANG
6
@ dapat dipilih Tergantung pada lingkungan Anda, cukup gunakan iflag (case-insensitive).
Gajus
20
Anda menolak Versi 1 hingga 3 dan 5. Mengapa?
iGEL
90

Jika Anda ingin memeriksa atau memvalidasi versi UUID tertentu , berikut adalah regex yang sesuai.

Perhatikan bahwa satu-satunya perbedaan adalah nomor versi , yang dijelaskan dalam 4.1.3. Versionbab UUID 4122 RFC .

Nomor versi adalah karakter pertama dari grup ketiga [VERSION_NUMBER][0-9A-F]{3}::

  • UUID v1:

    /^[0-9A-F]{8}-[0-9A-F]{4}-[1][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  • UUID v2:

    /^[0-9A-F]{8}-[0-9A-F]{4}-[2][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  • UUID v3:

    /^[0-9A-F]{8}-[0-9A-F]{4}-[3][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  • UUID v4:

    /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  • UUID v5:

    /^[0-9A-F]{8}-[0-9A-F]{4}-[5][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
Ivan Gabriele
sumber
Pola tidak termasuk huruf kecil. Itu juga harus berisi di a-fsebelah setiap A-Flingkup.
Paweł Psztyć
27
Pada iakhir regex menandainya sebagai case-sensitive.
johnhaley81
Pengubah pola tidak selalu dapat digunakan. Misalnya, dalam definisi openapi, polanya peka terhadap huruf besar-kecil
Stephane Janicaud
1
@StephaneJanicaud Di OpenAPI, Anda sebaiknya menggunakan formatpengubah dengan menyetelnya ke "uuid" daripada menggunakan regex untuk menguji UUID: swagger.io/docs/specification/data-models/data-types/#format
Ivan Gabriele
Terima kasih @IvanGabriele untuk tipnya, itu hanya sebuah contoh, ini adalah masalah yang sama ketika Anda tidak ingin memeriksa pola case insensitive.
Stephane Janicaud
35
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89AB][0-9a-f]{3}-[0-9a-f]{12}$/i

Regexp Gajus menolak UUID V1-3 dan 5, meskipun mereka valid.

iGEL
sumber
1
Tapi itu memungkinkan versi yang tidak valid (seperti 8 atau A) dan varian tidak valid.
Brice
Perhatikan bahwa AB dalam [89AB] [0-9a-f] adalah huruf besar dan sisa karakter yang diizinkan adalah huruf kecil. Itu telah menangkap saya dengan Python
Tony Sepia
17

[\w]{8}(-[\w]{4}){3}-[\w]{12} telah bekerja untuk saya dalam banyak kasus.

Atau jika Anda ingin benar-benar spesifik [\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}.

Sederhana sekali
sumber
3
Perlu dicatat bahwa, setidaknya di Jawa, cocok dengan _ serta digit heksadesimal. Mengganti \ w dengan \ p {XDigit} mungkin lebih tepat karena itu adalah kelas POSIX yang ditentukan untuk mencocokkan digit heksadesimal. Ini dapat rusak saat menggunakan rangkaian karakter Unicode lainnya.
oconnor0
1
@oconnor \wbiasanya berarti "karakter kata" Ini akan cocok dengan lebih dari hex-digit. Solusi Anda jauh lebih baik. Atau, untuk kompatibilitas / keterbacaan yang dapat Anda gunakan[a-f0-9]
exhuma
1
Berikut ini adalah string yang terlihat seperti regex dan cocok dengan pola-pola itu, tetapi merupakan regex yang tidak valid: 2wtu37k5-q174-4418-2cu2-276e4j82sv19
Travis Stevens
@ OleTraveler tidak benar, berfungsi seperti pesona. import re def valid_uuid(uuid): regex = re.compile('[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}', re.I) match = regex.match(uuid) return bool(match) valid_uuid('2wtu37k5-q174-4418-2cu2-276e4j82sv19')
Tomasz Wojcik
3
@tom String itu (2wt ...) adalah UUID yang tidak valid, tetapi pola yang diberikan dalam jawaban ini cocok dengan string yang menunjukkan bahwa itu adalah UUID yang valid. Sayang sekali saya tidak ingat mengapa UUID itu tidak valid.
Travis Stevens
10

Dalam python re, Anda dapat membentang dari alpha numerik ke huruf besar. Begitu..

import re
test = "01234ABCDEFGHIJKabcdefghijk01234abcdefghijkABCDEFGHIJK"
re.compile(r'[0-f]+').findall(test) # Bad: matches all uppercase alpha chars
## ['01234ABCDEFGHIJKabcdef', '01234abcdef', 'ABCDEFGHIJK']
re.compile(r'[0-F]+').findall(test) # Partial: does not match lowercase hex chars
## ['01234ABCDEF', '01234', 'ABCDEF']
re.compile(r'[0-F]+', re.I).findall(test) # Good
## ['01234ABCDEF', 'abcdef', '01234abcdef', 'ABCDEF']
re.compile(r'[0-f]+', re.I).findall(test) # Good
## ['01234ABCDEF', 'abcdef', '01234abcdef', 'ABCDEF']
re.compile(r'[0-Fa-f]+').findall(test) # Good (with uppercase-only magic)
## ['01234ABCDEF', 'abcdef', '01234abcdef', 'ABCDEF']
re.compile(r'[0-9a-fA-F]+').findall(test) # Good (with no magic)
## ['01234ABCDEF', 'abcdef', '01234abcdef', 'ABCDEF']

Itu membuat regex UUID Python paling sederhana:

re_uuid = re.compile("[0-F]{8}-([0-F]{4}-){3}[0-F]{12}", re.I)

Saya akan meninggalkannya sebagai latihan bagi pembaca untuk menggunakan timeit untuk membandingkan kinerja ini.

Nikmati. Simpan Pythonic ™!

CATATAN: Rentang itu juga akan cocok :;<=>?@', jika Anda curiga bisa memberikan Anda hasil positif palsu, jangan ambil jalan pintas. (Terima kasih Oliver Aubert untuk menunjukkannya di komentar.)

Bruno Bronosky
sumber
2
[0-F] memang akan cocok dengan 0-9 dan AF, tetapi juga karakter apa pun yang kode ASCII-nya adalah antara 57 (untuk 9) dan 65 (untuk A), dengan kata lain:: <=>? @ '.
Olivier Aubert
7
Jadi jangan gunakan kode yang disebutkan di atas kecuali jika Anda ingin mempertimbangkan: =>;? <;: - <@ =: - @ =; = - @; @: -> == @?> =:? = @; sebagai UUID yang valid :-)
Olivier Aubert
9

Menurut definisi, UUID adalah 32 digit heksadesimal, dipisahkan dalam 5 grup oleh tanda hubung, seperti yang telah Anda jelaskan. Anda tidak boleh ketinggalan dengan ekspresi reguler Anda.

http://en.wikipedia.org/wiki/Uuid#Definition

pix0r
sumber
2
Tidak benar. RFC4122 hanya memungkinkan [1-5] untuk digit versi, dan [89aAbB] untuk digit varian.
broofa
6

Jadi, saya pikir Richard Bronosky sebenarnya memiliki jawaban terbaik saat ini, tetapi saya pikir Anda dapat melakukan sedikit untuk membuatnya agak lebih sederhana (atau setidaknya terser):

re_uuid = re.compile(r'[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}', re.I)
Christopher Smith
sumber
1
Even terser:re_uuid = re.compile(r'[0-9a-f]{8}(?:-[0-9a-f]{4}){4}[0-9a-f]{8}', re.I)
Pedro Gimeno
5

Varian untuk C ++:

#include <regex>  // Required include

...

// Source string    
std::wstring srcStr = L"String with GIUD: {4d36e96e-e325-11ce-bfc1-08002be10318} any text";

// Regex and match
std::wsmatch match;
std::wregex rx(L"(\\{[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}\\})", std::regex_constants::icase);

// Search
std::regex_search(srcStr, match, rx);

// Result
std::wstring strGUID       = match[1];
Anton K
sumber
5

Untuk UUID yang dihasilkan pada OS X dengan uuidgen, pola regex adalah

[A-F0-9]{8}-[A-F0-9]{4}-4[A-F0-9]{3}-[89AB][A-F0-9]{3}-[A-F0-9]{12}

Verifikasi dengan

uuidgen | grep -E "[A-F0-9]{8}-[A-F0-9]{4}-4[A-F0-9]{3}-[89AB][A-F0-9]{3}-[A-F0-9]{12}"
Quanlong
sumber
2
$UUID_RE = join '-', map { "[0-9a-f]{$_}" } 8, 4, 4, 4, 12;

BTW, hanya memperbolehkan 4 pada salah satu posisi hanya berlaku untuk UUIDv4. Tetapi v4 bukan satu-satunya versi UUID yang ada. Saya telah bertemu v1 dalam latihan saya juga.

abufct
sumber
1

Jika menggunakan Posix regex ( grep -E, MySQL, dll.), Ini mungkin lebih mudah dibaca & diingat:

[[:xdigit:]]{8}(-[[:xdigit:]]{4}){3}-[[:xdigit:]]{12}
Walf
sumber
0

Untuk bash:

grep -E "[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}"

Sebagai contoh:

$> echo "f2575e6a-9bce-49e7-ae7c-bff6b555bda4" | grep -E "[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}"
f2575e6a-9bce-49e7-ae7c-bff6b555bda4
asherbar
sumber