J’ai fait un commentaire hier sur une réponse où quelqu’un avait utilisé [0123456789]
dans une expression régulière plutôt que [0-9]
ou \d
. J’ai dit qu’il était probablement plus efficace d’utiliser un spécificateur de plage ou de chiffre qu’un jeu de caractères.
J’ai décidé de tester cela aujourd’hui et j’ai découvert à ma grande surprise que (dans le moteur de regex C # au moins), il semble être moins efficace que les deux autres qui ne semblent pas beaucoup différer. Voici ma sortie de test sur 10000 chaînes aléatoires de 1000 caractères aléatoires avec 5077 contenant réellement un chiffre:
Regular expression \d took 00:00:00.2141226 result: 5077/10000 Regular expression [0-9] took 00:00:00.1357972 result: 5077/10000 63.42 % of first Regular expression [0123456789] took 00:00:00.1388997 result: 5077/10000 64.87 % of first
C’est une surprise pour deux raisons:
\d
est pire que [0-9]
. Y a-t-il plus à \d
que simplement un raccourci pour [0-9]
? Voici le code de test:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.Text.RegularExpressions; namespace SO_RegexPerformance { class Program { static void Main(ssortingng[] args) { var rand = new Random(1234); var ssortingngs = new List(); //10K random ssortingngs for (var i = 0; i < 10000; i++) { //Generate random string var sb = new StringBuilder(); for (var c = 0; c < 1000; c++) { //Add az randomly sb.Append((char)('a' + rand.Next(26))); } //In roughly 50% of them, put a digit if (rand.Next(2) == 0) { //Replace one character with a digit, 0-9 sb[rand.Next(sb.Length)] = (char)('0' + rand.Next(10)); } strings.Add(sb.ToString()); } var baseTime = testPerfomance(strings, @"\d"); Console.WriteLine(); var testTime = testPerfomance(strings, "[0-9]"); Console.WriteLine(" {0:P2} of first", testTime.TotalMilliseconds / baseTime.TotalMilliseconds); testTime = testPerfomance(strings, "[0123456789]"); Console.WriteLine(" {0:P2} of first", testTime.TotalMilliseconds / baseTime.TotalMilliseconds); } private static TimeSpan testPerfomance(List ssortingngs, ssortingng regex) { var sw = new Stopwatch(); int successes = 0; var rex = new Regex(regex); sw.Start(); foreach (var str in ssortingngs) { if (rex.Match(str).Success) { successes++; } } sw.Stop(); Console.Write("Regex {0,-12} took {1} result: {2}/{3}", regex, sw.Elapsed, successes, ssortingngs.Count); return sw.Elapsed; } } }
\d
vérifie tous les chiffres Unicode, alors que [0-9]
est limité à ces 10 caractères. Par exemple, les chiffres persans , ۱۲۳۴۵۶۷۸۹
, sont un exemple de chiffres Unicode qui correspondent à \d
, mais pas à [0-9]
.
Vous pouvez générer une liste de tous ces caractères en utilisant le code suivant:
var sb = new SsortingngBuilder(); for(UInt16 i = 0; i < UInt16.MaxValue; i++) { string str = Convert.ToChar(i).ToString(); if (Regex.IsMatch(str, @"\d")) sb.Append(str); } Console.WriteLine(sb.ToString());
Ce qui génère:
0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८ ९ ০১২৩৪৫৬৭৮৯੦੧੨੩੪੫੬੭੮੯૦૧૨૩૪૫૬૭૮૯ ୦୧୨୩୪୫୬୭୮୯ ௦௧௨௩௪௫௬௭௮௯౦౧౨౩౪౫౬౭౮౯೦೧೨೩೪೫೬೭೮೯൦൧൨൩൪൫൬൭൮൯๐๑๒๓๔๕๖๗๘๙໐໑໒໓໔໕໖໗໘໙༠༡༢༣༤༥༦༧༨༩၀၁၂၃၄၅၆၇၈၉႐႑႒႓႔႕႖႗႘႙០១២៣៤៥៦៧៨៩ ᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙ ᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏ ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙ ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙0123456789
Nous remercions ByteBlast de l’avoir remarqué dans les documents. Il suffit de changer le constructeur de regex:
var rex = new Regex(regex, RegexOptions.ECMAScript);
Donne de nouveaux timings:
Regex \d took 00:00:00.1355787 result: 5077/10000 Regex [0-9] took 00:00:00.1360403 result: 5077/10000 100.34 % of first Regex [0123456789] took 00:00:00.1362112 result: 5077/10000 100.47 % of first
De “Est-ce que” \ d “dans regex signifie un chiffre? :
[0-9]
n’est pas équivalent à\d
.[0-9]
correspond uniquement aux caractères0123456789
, tandis que\d
correspond à[0-9]
et aux autres caractères numériques, par exemple les chiffres arabes orientaux٠١٢٣٤٥٦٧٨٩
Un ajout à la première réponse de Sina Iravianian , voici une version .NET 4.5 (puisque seule cette version prend en charge la sortie UTF16, voir les trois premières lignes) de son code, en utilisant toute la gamme des points de code Unicode. En raison de l’absence de prise en charge appropriée des avions Unicode supérieurs, de nombreuses personnes ne sont pas conscientes de toujours rechercher et inclure les plans Unicode supérieurs. Néanmoins, ils contiennent parfois des caractères importants.
Mettre à jour
Puisque \d
ne supporte pas les caractères non-BMP dans regex (merci xanatos ), voici une version qui utilise la firebase database de caractères Unicode
public static void Main() { var unicodeEncoding = new UnicodeEncoding(!BitConverter.IsLittleEndian, false); Console.InputEncoding = unicodeEncoding; Console.OutputEncoding = unicodeEncoding; var sb = new SsortingngBuilder(); for (var codePoint = 0; codePoint <= 0x10ffff; codePoint++) { var isSurrogateCodePoint = codePoint <= UInt16.MaxValue && ( char.IsLowSurrogate((char) codePoint) || char.IsHighSurrogate((char) codePoint) ); if (isSurrogateCodePoint) continue; var codePointString = char.ConvertFromUtf32(codePoint); foreach (var category in new []{ UnicodeCategory.DecimalDigitNumber, UnicodeCategory.LetterNumber, UnicodeCategory.OtherNumber}) { sb.AppendLine($"{category}"); foreach (var ch in charInfo[category]) { sb.Append(ch); } sb.AppendLine(); } } Console.WriteLine(sb.ToString()); Console.ReadKey(); }
Cession de la sortie suivante:
DecimalDigitNumber 012345678901234567890123456789߀߁߂߃߄߅߆߇߈߉012345678 9 01২345678901234567890123456789 ୦୧୨୩୪୫୬୭୮୯ 0123456789012345678901234567890123456789 ෦෧෨෩෪෫෬෭෮෯ 012345678901234567890123456789012345678901234567890123456789 ᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙ ᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏ ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙ ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙꧰꧱꧲꧳꧴꧵꧶꧷꧸꧹꩐꩑꩒ ꩔꩕꩖꩗꩘꩙꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹0123456789𐒠𐒡𐒢𐒣𐒤𐒥𐒦𐒧𐒨𐒩 𑁦𑁧𑁨𑁩𑁪𑁫𑁬𑁭𑁮𑁯 𑃰𑃱𑃲𑃳𑃴𑃵𑃶𑃷𑃸𑃹 𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿 𑇐𑇑𑇒𑇓𑇔𑇕𑇖𑇗𑇘𑇙 𑋰𑋱𑋲𑋳𑋴𑋵𑋶𑋷𑋸𑋹 𑓐𑓑𑓒𑓓𑓔𑓕𑓖𑓗𑓘𑓙 𑙐𑙑𑙒𑙓𑙔𑙕𑙖𑙗𑙘𑙙 𑛀𑛁𑛂𑛃𑛄𑛅𑛆𑛇𑛈𑛉 𑜰𑜱𑜲𑜳𑜴𑜵𑜶𑜷𑜸𑜹 𑣠𑣡𑣢𑣣𑣤𑣥𑣦𑣧𑣨𑣩 𖩠𖩡𖩢𖩣𖩤𖩥𖩦𖩧𖩨𖩩 𖭐𖭑𖭒𖭓𖭔𖭕𖭖𖭗𖭘𖭙𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡𝟢𝟣𝟤𝟥𝟦𝟧𝟨𝟩𝟪𝟫𝟬𝟭𝟮𝟯𝟰𝟱𝟲𝟳𝟴𝟵𝟶𝟷𝟸𝟹𝟺𝟻𝟼𝟽𝟾𝟿
Numéro de lettre
ᛮᛯᛰⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↀↁↂↅↆↇↈ〇〡〢〣〤〥〦〧〨〩〸〹〺ꛦꛧꛨꛩꛪꛫꛬꛭꛮꛯ 𐅀𐅁𐅂𐅃𐅄𐅅𐅆𐅇𐅈𐅉𐅊𐅋𐅌𐅍𐅎𐅏𐅐𐅑𐅒𐅓𐅔𐅕𐅖𐅗𐅘𐅙𐅚𐅛𐅜𐅝𐅞𐅟𐅠𐅡𐅢𐅣𐅤𐅥𐅦𐅧𐅨𐅩𐅪𐅫𐅬𐅭𐅮𐅯𐅰𐅱𐅲𐅳𐅴 𐍁𐍊 𐏑𐏒𐏓𐏔𐏕 𒐀𒐁𒐂𒐃𒐄𒐅𒐆𒐇𒐈𒐉𒐊𒐋𒐌𒐍𒐎𒐏𒐐𒐑𒐒𒐓𒐔𒐕𒐖𒐗𒐘𒐙𒐚𒐛𒐜𒐝𒐞𒐟𒐠𒐡𒐢𒐣𒐤𒐥𒐦𒐧𒐨𒐩𒐪𒐫𒐬𒐭𒐮𒐯𒐰𒐱𒐲𒐳𒐴𒐵𒐶𒐷𒐸𒐹𒐺𒐻𒐼𒐽𒐾𒐿𒑀𒑁𒑂𒑃𒑄𒑅𒑆𒑇𒑈𒑉𒑊𒑋𒑌𒑍𒑎𒑏𒑐𒑑𒑒𒑓𒑔𒑕𒑖𒑗𒑘𒑙𒑚𒑛𒑜𒑝𒑞𒑟𒑠𒑡𒑢𒑣𒑤𒑥𒑦𒑧𒑨𒑩𒑪𒑫𒑬𒑭𒑮
OtherNumber ²³¹¼½¾৴৵৶৷৸৹ ୲୳୴୵୶୷ ௰௱௲ ౸౹౺౻౼౽౾ ൰൱൲൳൴൵ ༪ ༫ ༬ ៳ ៴ ៵ ៶ ៷ ៸ ៹ ᧚⁰⁴⁵⁶⁷⁸⁹₀₁₂₃₄₅₆₇₈₉⅐⅑⅒⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞⅟↉①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓ ⳽ ㆒ ㆓ ㆔ ㆕ ㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㉈㉉㉊㉋㉌㉍㉎㉏㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿꠰꠱꠲꠳꠴꠵𐄇𐄈𐄉𐄊𐄋𐄌𐄍𐄎𐄏𐄐𐄑𐄒𐄓𐄔𐄕𐄖𐄗𐄘𐄙𐄚𐄛𐄜𐄝𐄞𐄟𐄠𐄡𐄢𐄣𐄤𐄥 𐌠𐌡𐌢𐌣 𐡘𐡙𐡚𐡛𐡜𐡝𐡞𐡟 𐡹𐡺𐡻𐡼𐡽𐡾𐡿 𐢧𐢨𐢩𐢪𐢫𐢬𐢭𐢮𐢯 𐣻𐣼𐣽𐣾𐣿 𐤖𐤗𐤘𐤙𐤚𐤛 𐦼𐦽𐧀𐧁𐧂𐧃𐧄𐧅𐧆𐧇𐧈𐧉𐧊𐧋𐧌𐧍𐧎𐧏𐧒𐧓𐧔𐧕𐧖𐧗𐧘𐧙𐧚𐧛𐧜𐧝𐧞𐧟𐧠𐧡𐧢𐧣𐧤𐧥𐧦𐧧𐧨𐧩𐧪𐧫𐧬𐧭𐧮𐧯𐧰𐧱𐧲𐧳𐧴𐧵𐧶𐧷𐧸𐧹𐧺𐧻𐧼𐧽𐧾𐧿 𐩀𐩁𐩂𐩃𐩄𐩅𐩆𐩇 𑁒𑁓𑁔𑁕𑁖𑁗𑁘𑁙𑁚𑁛𑁜𑁝𑁞𑁟𑁠𑁡𑁢𑁣𑁤𑁥 𐪝𐪞𐪟 𑇡𑇢 𑇣𑇤𑇥𑇦𑇧𑇨𑇩𑇪𑇫𑇬𑇭𑇮𑇯𑇰𑇱𑇲𑇳𑇴 𑜺𑜻 𑣪𑣫𑣬𑣭𑣮𑣯𑣰𑣱𑣲 𖭛𖭜𖭝𖭞𖭟𖭠𖭡𝍠𝍡𝍢𝍣𝍤𝍥𝍦𝍧𝍨𝍩𝍪𝍫𝍬𝍭𝍮𝍯𝍰𝍱 𞣇𞣈𞣉𞣊𞣋𞣌𞣍𞣎𞣏🄀🄁🄂🄃🄄🄅🄆🄇🄈🄉🄊🄋🄌
\ d vérifie tout Unicode, alors que [0-9] est limité à ces 10 caractères. Si seulement 10 chiffres, vous devriez utiliser. Autres je recommande d’utiliser \ d , Parce que l’écriture moins.
\d
va être moins efficace car il doit être converti pour la comparaison.
Par exemple, si je voulais que Regex trouve des adresses IP, je préférerais que nous [0123456789]
\d
que [0123456789]
ou même [0-9]
pour représenter un chiffre quelconque.
D’une manière générale, dans mon utilisation de Regex, fonctionne si plus important que la vitesse.