使用正则表达式搜索文本中的UUID


224

我正在使用正则表达式在文本块中搜索UUID。目前,我所基于的假设是,所有UUID都将遵循8-4-4-4-12十六进制数字的样式。

谁能想到一个用例,这个假设将是无效的,并且会导致我错过一些UUID?


6年前的这个问题是为了帮助我进行一个项目以查找文本中的信用卡。随后,我开源了从我的博客文章中链接的代码,该代码解释了UUID在搜索信用卡时造成的细微差别guyellisrocks.com/2013/11/…–
Guy

4
对UUID正则表达式模式匹配的搜索将我带到了该堆栈溢出文章,但可接受的答案实际上不是答案。此外,您在问题下方的评论中提供的链接也没有模式(除非我遗漏了某些内容)。这些答案之一是您最终使用的东西吗?
塔斯(Tass)2016年

如果您遵循以我发布的链接开头的链接的兔子,那么您可能会在GitHub中遇到这一行,该行具有我最终使用的正则表达式。(很难理解,这很难理解。)该代码和该文件可能会对您有所帮助:github.com/guyellis/CreditCard/blob/master/Company.CreditCard/…–
Guy

1
这些答案似乎都没有为仅有效RFC 4122 UUID的所有变体提供单个正则表达式。但似乎在这里给出了这样的答案:stackoverflow.com/a/13653180/421049
Garret Wilson

Answers:


41

我同意,根据定义,您的正则表达式不会丢失任何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

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]!由于是十六进制!您的正则表达式(按原样)可能返回假阳性。
2011年

13
在某些情况下,您甚至可能希望将其设为[a-fA-F0-9]或[A-F0-9]。
汉斯·彼得·斯特尔

22
@ cyber-monk:[0-9a-f]的含义和速度与[a-f0-9]和[0123456789abcdef]相同,因为正则表达式始终变为状态机,每个十六进制数字都变为进入状态表。有关其工作原理的切入点,请参见en.wikipedia.org/wiki/Nondeterministic_finite_automaton
JesperSM

10
这个解决方案不是很正确。根据RFC4122,它匹配具有无效版本和变体字符的ID。在这方面,@ Gajus的解决方案更正确。另外,RFC允许在输入中使用大写字符,因此添加[AF]将是适当的。
broofa 2013年

4
@broofa,我看到您确实对每个仅匹配与RFC一致的UUID的人都感到满意。但是,我认为必须指出很多次这一事实可以证明并非所有UUID都会使用RFC版本和变体指示器。UUID定义en.wikipedia.org/wiki/Uuid#Definition声明了一个简单的8-4-4-4-12模式和2 ^ 128个可能性。RFC仅代表其一部分。那你想搭配什么?子集还是全部?
布鲁诺·布罗诺斯基

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并非所有语言都提供该选项。这个答案中的原始模式在Go中对我有用。该/.../i版本没有。
克里斯·雷德福

110

版本4 UUID的格式为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。
2013年

8
也需要接受[AF]。根据RFC4122的第3节:'十六进制值“ a”至“ f”输出为小写字符,并且对输入 ' 不区分大小写。也(:?8|9|A|B)可能更具可读性,例如[89aAbB]
broofa

1
需要复制@broofa的修改;-您的排除小写字母A或
B。– ELLIOTTCABLE

6
@elliottcable根据您的环境,仅使用i(不区分大小写)标志。
Gajus 2014年

20
您拒绝版本1至3和5。为什么?
iGEL 2014年

90

如果要检查或验证特定的UUID版本,请参见以下相应的正则表达式。

请注意,唯一的区别是版本号,这在UUID 4122 RFC的4.1.3. Version章节中进行了说明。

版本号是第三组的第一个字符[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范围旁边包含。
帕维尔Psztyć

27
i在正则表达式标记为不区分大小写的端部。
johnhaley81

模式修改器不能总是使用。例如,在openapi定义中,模式区分大小写
Stephane Janicaud

1
@StephaneJanicaud在OpenAPI中,您应该通过将format修饰符设置为“ uuid”来使用它,而不是使用正则表达式来测试UUID: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)和无效的变体。
布莱斯

请注意,[89AB] [0-9a-f]中的AB为大写字母,其余允许的字符为小写字母。它让我陷入了Python
Tony Sepia

17

[\w]{8}(-[\w]{4}){3}-[\w]{12} 在大多数情况下为我工作。

或者,如果您想真正具体一点[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}


3
值得注意的是,至少在Java中\ w与_以及十六进制数字匹配。用\ p {XDigit}替换\ w可能更合适,因为这是为匹配十六进制数字而定义的POSIX类。使用其他Unicode字符集时,这可能会中断。
oconnor0 2011年

1
@oconnor \w通常表示“单词字符”,它将比十六进制数字匹配得多。您的解决方案要好得多。或者,出于兼容性/可读性的考虑,您可以使用[a-f0-9]
exhuma 2011年

1
这是一个看起来像正则表达式且与这些模式匹配的字符串,但是它是无效的正则表达式:2wtu37k5-q174-4418-2cu2-276e4j82sv19
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无效。
特拉维斯·史蒂文斯

10

在python re中,您可以从数字到大写字母。所以..

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正则表达式:

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

我会把它留给读者作为练习,使用timeit来比较它们的性能。

请享用。保持Pythonic™!

注意:这些跨度也将匹配,:;<=>?@'因此,如果您怀疑这会给您带来误报,请不要使用快捷方式。(感谢奥利弗·奥伯特在评论中指出这一点。)


2
[0-F]实际上将匹配0-9和AF,但也匹配ASCII码介于57(对于9)和65(对于A)之间的任何字符,即:: <=>?@'中的任何一个。
Olivier Aubert

7
因此,除非要考虑:=>;?<;:-<@ =:-@ =; =-@; @:-> == @?> =:?= @ ;,否则不要使用上述代码。作为有效的UUID :-)
Olivier Aubert


6

因此,我认为Richard Bronosky实际上是迄今为止最好的答案,但是我认为您可以做一些使其更简单(或至少更简短)的方法:

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

对于在OS X上使用生成的UUID uuidgen,正则表达式为

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

顺便说一句,其中一个位置仅允许4个仅对UUIDv4有效。但是v4并不是唯一存在的UUID版本。我在实践中也遇到过v1。


1

如果使用Posix正则表达式(grep -E,MySQL等),则可能更容易阅读和记住:

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

0

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

例如:

$> 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.