ค้นหา UUID ในข้อความด้วย regex


224

ฉันกำลังค้นหา UUID ในกลุ่มข้อความโดยใช้ regex ขณะนี้ฉันอาศัยสมมติฐานที่ว่า UUID ทั้งหมดจะเป็นไปตามรูปแบบเลขฐานสิบหก 8-4-4-4-12 เลขฐานสิบหก

ใครสามารถคิดกรณีการใช้งานที่สมมติฐานนี้จะไม่ถูกต้องและจะทำให้ฉันพลาด UUID บาง


คำถามนี้เมื่อ 6 ปีก่อนคือช่วยฉันในการหาโครงการบัตรเครดิตแบบข้อความ ผมเคยต่อมาโอเพนซอร์ซโค้ดซึ่งจะเชื่อมโยงจากโพสต์บล็อกของฉันซึ่งจะอธิบายแตกต่างกันนิดหน่อยที่ UUIDs ได้ก่อให้เกิดความเมื่อค้นหาบัตรเครดิตguyellisrocks.com/2013/11/...
ผู้ชาย

4
การค้นหาการจับคู่รูปแบบการแสดงออกปกติ UUID นำฉันไปที่โพสต์ล้นสแต็กนี้ แต่คำตอบที่ยอมรับแล้วจริง ๆ แล้วไม่ใช่คำตอบ นอกจากนี้ลิงก์ที่คุณให้ไว้ในความคิดเห็นด้านล่างคำถามของคุณยังไม่มีรูปแบบ (ยกเว้นว่าฉันขาดอะไรไป) เป็นหนึ่งในคำตอบที่คุณใช้ใช่มั้ย
Tass

หากคุณติดตามกระต่ายวอร์เรนของลิงก์ที่เริ่มต้นด้วยโพสต์ที่ฉันโพสต์คุณอาจเจอในบรรทัดนี้ใน GitHub ซึ่งมี regex ที่ฉันใช้ในที่สุด (เข้าใจได้ว่าเป็นการยากที่จะหา) รหัสนั้นและไฟล์ดังกล่าวอาจช่วยคุณได้: github.com/guyellis/CreditCard/blob/master/Company.CreditCard/ …
Guy

1
ดูเหมือนว่าไม่มีคำตอบใด ๆ ที่จะให้ regex เพียงหนึ่งเดียวสำหรับตัวแปรทั้งหมดของ UCID ที่ถูกต้องของ RFC 4122 เท่านั้น แต่ดูเหมือนว่าจะได้รับคำตอบเช่นนี้: stackoverflow.com/a/13653180/421049
Garret Wilson

คำตอบ:


41

ฉันยอมรับว่าตามนิยาม regex ของคุณจะไม่พลาด UUID ใด ๆ อย่างไรก็ตามอาจมีประโยชน์ที่จะต้องทราบว่าหากคุณกำลังค้นหาตัวระบุที่ไม่ซ้ำกันทั่วโลกของ Microsoft (GUID) โดยเฉพาะมีการแสดงสตริงที่เทียบเท่าห้ารายการสำหรับ 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}}" 

3
จะพบรูปแบบแรกภายใต้สถานการณ์ใด เช่นมีฟังก์ชั่น. Net ที่จะตัดยัติภังค์หรือส่งคืน GUID โดยไม่ต้องใส่เครื่องหมายขีดกลางหรือไม่
Guy

1
คุณสามารถรับได้ด้วย myGuid.ToString ("N")
Panos

462

regex สำหรับ uuid คือ:

\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b

19
ทำอย่างนั้น[a-f0-9]! มันเป็นฐานสิบหก! regex ของคุณ (ตามเดิม) สามารถส่งคืนผลบวกปลอม
exhuma

13
ในบางกรณีคุณอาจต้องการ [a-fA-F0-9] หรือ [A-F0-9]
Hans-Peter Störr

22
@ cyber-monk: [0-9a-f] เหมือนกับ [a-f0-9] และ [0123456789abcdef] ในความหมายและความเร็วตั้งแต่ regex กลายเป็นเครื่องรัฐต่อไปโดยที่เลขฐานสิบหกแต่ละเลขกลายเป็น รายการในตารางสถานะ สำหรับจุดเริ่มต้นเกี่ยวกับวิธีการทำงานของมันให้ดูen.wikipedia.org/wiki/Nondeterministic_finite_automaton
JesperSM

10
วิธีนี้ไม่ถูกต้องนัก มันตรงกับ ID ที่มีรุ่นและอักขระที่ไม่ถูกต้องต่อ RFC4122 วิธีการแก้ปัญหา @Gajus นั้นถูกต้องมากขึ้นในเรื่องนั้น นอกจากนี้ RFC ยังอนุญาตให้ใช้อักขระตัวพิมพ์ใหญ่ในอินพุตดังนั้นการเพิ่ม [AF] จึงเหมาะสม
broofa

4
@broofa ฉันเห็นว่าคุณถูกกำหนดให้ทุกคนจับคู่เฉพาะ UUID ที่สอดคล้องกับ RFC อย่างไรก็ตามฉันคิดว่าความจริงที่ว่าคุณต้องชี้ประเด็นนี้มาหลายครั้งแล้วเป็นตัวบ่งชี้ที่มั่นคงซึ่งไม่ใช่ UUID ทั้งหมดที่จะใช้เวอร์ชั่น RFC และตัวบ่งชี้ชุดตัวเลือก นิยาม UUID en.wikipedia.org/wiki/Uuid#Definitionระบุรูปแบบ 8-4-4-4-12 อย่างง่ายและความเป็นไปได้ 2 ^ 128 RFC แสดงถึงชุดย่อยเท่านั้น ดังนั้นคุณต้องการจับคู่อะไร ชุดย่อยหรือทั้งหมดของพวกเขา?
Bruno Bronosky

120

@ivelin: UUID สามารถมีตัวพิมพ์ใหญ่ได้ ดังนั้นคุณจะต้อง toLowerCase () สตริงหรือใช้:

[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}

จะมีเพียงแค่แสดงความคิดเห็นนี้ แต่ตัวแทนไม่พอ :)


22
โดยปกติคุณสามารถจัดการสิ่งนี้ได้โดยการกำหนดรูปแบบเป็นตัวพิมพ์เล็กและตัวพิมพ์เล็กที่มี i หลังจากรูปแบบนี้ทำให้รูปแบบที่สะอาดขึ้น: / [0-9a-f] {8} - [0-9a-f] {4} - [0 -9a-f] {4} - [0-9a-f] {4} - [0-9a-f] {12} / i
Thomas Bindzus

@ThomasBindzus ตัวเลือกนั้นไม่มีให้บริการในทุกภาษา รูปแบบดั้งเดิมของคำตอบนี้ใช้ได้กับฉันในโก /.../iรุ่นไม่ได้
Chris Redford

110

UUID เวอร์ชัน 4 มีรูปแบบ xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx โดยที่ x เป็นเลขฐานสิบหกหลักใด ๆ และ y คือหนึ่งใน 8, 9, A หรือ B เช่น f47ac10b-58cc-4372-a567-0e02b2c3d479

แหล่งที่มา: http://en.wikipedia.org/wiki/Uuid#Definition

ดังนั้นนี่คือเทคนิคที่ถูกต้องมากขึ้น:

/[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/

ฉันไม่คิดว่าคุณหมายถึง az
Bruno Bronosky

8
ต้องยอมรับ [AF] ด้วย ตามส่วนที่ 3 ของ RFC4122: 'ค่าเลขฐานสิบหก "a" ถึง "f" จะถูกส่งออกเป็นอักขระตัวพิมพ์เล็กและไม่คำนึงถึงขนาดตัวพิมพ์ของอินพุต ' นอกจากนี้ยัง(:?8|9|A|B)อาจอ่านได้มากขึ้นอีกด้วย[89aAbB]
broofa

1
จำเป็นต้องคัดลอกการดัดแปลงของ @ broofa เป็นของคุณไม่รวมตัวพิมพ์เล็ก A หรือ B
ELLIOTTCABLE

6
@elliottcable ขึ้นอยู่กับสภาพแวดล้อมของคุณเพียงใช้iแฟล็ก(ตัวพิมพ์เล็กและตัวพิมพ์ใหญ่)
Gajus

20
คุณกำลังปฏิเสธเวอร์ชัน 1 ถึง 3 และ 5 เพราะอะไร
iGEL

90

หากคุณต้องการตรวจสอบหรือตรวจสอบความถูกต้องของเวอร์ชัน UUID เฉพาะนี่คือ regexes ที่เกี่ยวข้อง

โปรดทราบว่าแตกต่างเพียงอย่างเดียวคือหมายเลขรุ่นซึ่งจะอธิบายใน4.1.3. VersionบทของUUID 4122 RFC

หมายเลขเวอร์ชันเป็นอักขระตัวแรกของกลุ่มที่สาม[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

รูปแบบไม่รวมตัวอักษรตัวพิมพ์เล็ก มันควรจะมีa-fถัดจากแต่ละA-Fขอบเขต
PawełPsztyć

27
iในตอนท้ายของเครื่องหมาย regex มันเป็นกรณีตาย
johnhaley81

ไม่สามารถใช้ตัวดัดแปลงรูปแบบได้เสมอ ตัวอย่างเช่นในคำจำกัดความของ openapi รูปแบบจะต้องตรงตามตัวพิมพ์ใหญ่และตัวพิมพ์ใหญ่
Stephane Janicaud

1
@StephaneJanicaud ใน OpenAPI คุณควรใช้formatตัวปรับเปลี่ยนโดยตั้งค่าเป็น "uuid" แทนที่จะใช้ regex เพื่อทดสอบ UUIDs: swagger.io/docs/specification/data-models/data-types/#format
Ivan Gabriele

ขอบคุณ @IvanGabriele สำหรับเคล็ดลับมันเป็นเพียงตัวอย่างมันเป็นปัญหาเดียวกันเมื่อคุณไม่ได้ตรวจสอบรูปแบบที่ไม่สำคัญ
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

Gajus 'regexp ปฏิเสธ UUID V1-3 และ 5 แม้ว่ามันจะถูกต้องก็ตาม


1
แต่อนุญาตรุ่นที่ไม่ถูกต้อง (เช่น 8 หรือ A) และตัวแปรที่ไม่ถูกต้อง
Brice

โปรดทราบว่า AB ใน [89AB] [0-9a-f] เป็นตัวพิมพ์ใหญ่และตัวอักษรที่เหลือจะเป็นตัวพิมพ์เล็ก มันทำให้ฉันประหลาดใจใน Python
Tony Sepia

17

[\w]{8}(-[\w]{4}){3}-[\w]{12} ได้ทำงานให้ฉันในกรณีส่วนใหญ่

[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}หรือถ้าคุณต้องการที่จะเฉพาะเจาะจงจริงๆ


3
มันน่าสังเกตว่า \ w ใน Java อย่างน้อยตรงกับ _ รวมทั้งเป็นเลขฐานสิบหก การแทนที่ \ w ด้วย \ p {XDigit} อาจเหมาะสมกว่าเนื่องจากเป็นคลาส POSIX ที่กำหนดไว้สำหรับการจับคู่ตัวเลขฐานสิบหกที่ตรงกัน สิ่งนี้อาจแตกหักเมื่อใช้ Unicode charsets อื่น
oconnor0

1
@oconnor \wมักจะหมายถึง "คำตัวอักษร" มันจะตรงกับมากกว่าตัวเลขฐานสิบหก ทางออกของคุณดีขึ้นมาก หรือเพื่อความเข้ากันได้ / อ่านง่ายคุณสามารถใช้[a-f0-9]
exhuma

1
นี่คือสตริงที่ดูเหมือน regex และจับคู่รูปแบบเหล่านั้น แต่เป็น regex ที่ไม่ถูกต้อง: 2wtu37k5-q174-4418-2cu2-276e4j82sv19 2
Travis Stevens

@OleTraveler ไม่เป็นความจริงมีเสน่ห์เหมือนงาน 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 สตริงนั้น (2wt ... ) เป็น UUID ที่ไม่ถูกต้อง แต่รูปแบบที่ให้ไว้ในคำตอบนี้ตรงกับสตริงที่ระบุว่าเป็นเท็จ UUID ที่ถูกต้อง มันแย่มากที่ฉันจำไม่ได้ว่าทำไม UUID ถึงไม่ถูกต้อง
Travis Stevens

10

ในภาษาไพ ธ อนคุณสามารถขยายจากตัวเลขไปเป็นอัลฟาตัวพิมพ์ใหญ่ ดังนั้น..

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']

นั่นทำให้ Python UUID regex ที่ง่ายที่สุด:

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

ฉันจะปล่อยให้มันเป็นแบบฝึกหัดให้ผู้อ่านใช้ timeit เพื่อเปรียบเทียบประสิทธิภาพของสิ่งเหล่านี้

สนุก. เก็บ Pythonic ™!

หมายเหตุ:ช่วงเวลาเหล่านั้นจะตรงกัน:;<=>?@'เช่นกันหากคุณสงสัยว่าอาจให้ผลบวกเป็นเท็จแก่คุณอย่าใช้ทางลัด (ขอบคุณ Oliver Aubert ที่ชี้ให้เห็นในความคิดเห็น)


2
[0-F] จะตรงกับ 0-9 และ AF แต่ตัวอักษรใด ๆ ที่มีรหัส ASCII อยู่ระหว่าง 57 (สำหรับ 9) และ 65 (สำหรับ A) นั่นคือการพูดใด ๆ ของ:; <=>? @ '
Olivier Aubert

7
ดังนั้นอย่าใช้รหัสข้างต้นยกเว้นถ้าคุณต้องการพิจารณา: =>;? <;: - <@ =: - @ =; = - @; @: -> == @?> =:? = @; ในฐานะ UUID ที่ถูกต้อง :-)
Olivier Aubert

9

ตามคำนิยาม UUID คือเลขฐานสิบหก 32 หลักคั่นด้วยเครื่องหมายยัติภังค์ 5 กลุ่มตามที่คุณอธิบายไว้ คุณไม่ควรพลาดอะไรกับการแสดงออกปกติของคุณ

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


2
ไม่ถูกต้อง. RFC4122 อนุญาตเฉพาะ [1-5] สำหรับรุ่นหลักและ [89aAbB] สำหรับหลักชุดตัวเลือก
broofa

6

ดังนั้นฉันคิดว่า Richard Bronosky มีคำตอบที่ดีที่สุดในปัจจุบัน แต่ฉันคิดว่าคุณสามารถทำได้เล็กน้อยเพื่อให้ง่ายขึ้น (หรืออย่างน้อย terer):

re_uuid = re.compile(r'[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}', re.I)

1
คู่หู:re_uuid = re.compile(r'[0-9a-f]{8}(?:-[0-9a-f]{4}){4}[0-9a-f]{8}', re.I)
Pedro Gimeno

5

ตัวแปรสำหรับ 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];

5

สำหรับ UUID ที่สร้างบน OS X ด้วยuuidgenรูปแบบ regex คือ

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

ยืนยันด้วย

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}"

2
$UUID_RE = join '-', map { "[0-9a-f]{$_}" } 8, 4, 4, 4, 12;

BTW ที่อนุญาตเพียง 4 ในตำแหน่งใดตำแหน่งหนึ่งเท่านั้นที่ใช้ได้สำหรับ UUIDv4 แต่ v4 ไม่ใช่รุ่น UUID เดียวที่มีอยู่ ฉันได้พบ v1 ในการฝึกฝนของฉันเช่นกัน


1

หากใช้ Posix regex ( grep -E, MySQL, ฯลฯ ) การอ่านและจดจำอาจง่ายกว่า:

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

0

สำหรับทุบตี:

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

ตัวอย่างเช่น:

$> 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.