나는 누군가가 사용했던 답변에 어제 코멘트를 만든 [0123456789]
A의 정규 표현식 보다는 [0-9]
나 \d
. 문자 세트보다 범위 또는 숫자 지정자를 사용하는 것이 더 효율적이라고 말했습니다.
나는 오늘 그것을 테스트하기로 결정했고 (C # 정규식 엔진에서) \d
크게 다르지 않은 다른 두 엔진 보다 효율성이 떨어지는 것으로 놀랐 습니다. 다음은 실제로 숫자가 포함 된 5077의 1000 개의 임의 문자로 구성된 10000 개의 임의 문자열에 대한 테스트 결과입니다.
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
두 가지 이유로 놀랍습니다.
- 범위가 세트보다 훨씬 효율적으로 구현 될 것이라고 생각했을 것입니다.
- 왜
\d
보다 더 나쁜지 이해할 수 없습니다[0-9]
.\d
단순히 속기보다 더 많은 것이[0-9]
있습니까?
테스트 코드는 다음과 같습니다.
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(string[] args)
{
var rand = new Random(1234);
var strings = new List<string>();
//10K random strings
for (var i = 0; i < 10000; i++)
{
//Generate random string
var sb = new StringBuilder();
for (var c = 0; c < 1000; c++)
{
//Add a-z 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<string> strings, string regex)
{
var sw = new Stopwatch();
int successes = 0;
var rex = new Regex(regex);
sw.Start();
foreach (var str in strings)
{
if (rex.Match(str).Success)
{
successes++;
}
}
sw.Stop();
Console.Write("Regex {0,-12} took {1} result: {2}/{3}", regex, sw.Elapsed, successes, strings.Count);
return sw.Elapsed;
}
}
}
답변
\d
모든 유니 코드 숫자를 확인하지만 [0-9]
이 10 자로 제한됩니다. 예를 들어, 페르시아 숫자 () ۱۲۳۴۵۶۷۸۹
는와 일치 \d
하지만 일치 하지 않는 유니 코드 숫자의 예입니다 [0-9]
.
다음 코드를 사용하여 이러한 모든 문자 목록을 생성 할 수 있습니다.
var sb = new StringBuilder();
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());
어떤 생성 :
0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८ ९ ০১২৩৪৫৬৭৮৯੦੧੨੩੪੫੬੭੮੯૦૧૨૩૪૫૬૭૮૯ ୦୧୨୩୪୫୬୭୮୯ ௦௧௨௩௪௫௬௭௮௯౦౧౨౩౪౫౬౭౮౯೦೧೨೩೪೫೬೭೮೯൦൧൨൩൪൫൬൭൮൯๐๑๒๓๔๕๖๗๘๙໐໑໒໓໔໕໖໗໘໙༠༡༢༣༤༥༦༧༨༩၀၁၂၃၄၅၆၇၈၉႐႑႒႓႔႕႖႗႘႙០១២៣៤៥៦៧៨៩ ᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙ ᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏ ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙ ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙01234466789
답변
문서에서이를 알린 ByteBlast의 크레딧입니다. 정규식 생성자를 변경하면됩니다.
var rex = new Regex(regex, RegexOptions.ECMAScript);
새로운 타이밍을 제공합니다 :
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
답변
From 정규식의 “\ d”는 숫자를 의미합니까? :
[0-9]
에 해당하지 않습니다\d
. 문자[0-9]
만 일치 하고 일치 및 다른 숫자 문자 (예 : 동부 아라비아 숫자)0123456789
\d
[0-9]
٠١٢٣٤٥٦٧٨٩
답변
에 추가 상부 않음 로부터 시나 Iravianian은 여기 유니 코드 코드 포인트들의 전체 범위를 사용하여 자신의 코드 (제 산신 CF 해당 버전 지원의 UTF16 출력 보낸) 닷넷 4.5 버전이다. 더 높은 유니 코드 평면을 제대로 지원하지 않기 때문에 많은 사람들이 항상 상위 유니 코드 평면을 확인하고 포함하는 것을 인식하지 못합니다. 그럼에도 불구하고 그들은 때때로 중요한 인물들을 포함하고 있습니다.
최신 정보
\d
정규식에서 비 BMP 문자를 지원하지 않기 때문에 ( xanatos 덕분에 ) 여기에 유니 코드 문자 데이터베이스를 사용하는 버전
public static void Main()
{
var unicodeEncoding = new UnicodeEncoding(!BitConverter.IsLittleEndian, false);
Console.InputEncoding = unicodeEncoding;
Console.OutputEncoding = unicodeEncoding;
var sb = new StringBuilder();
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();
}
다음과 같은 결과가 나옵니다.
DecimalDigitNumber 0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८ ९ ০১২৩৪৫৬৭৮৯੦੧੨੩੪੫੬੭੮੯૦૧૨૩૪૫૬૭૮૯ ୦୧୨୩୪୫୬୭୮୯ ௦௧௨௩௪௫௬௭௮௯౦౧౨౩౪౫౬౭౮౯೦೧೨೩೪೫೬೭೮೯൦൧൨൩൪൫൬൭൮൯ ෦෧෨෩෪෫෬෭෮෯ ๐๑๒๓๔๕๖๗๘๙໐໑໒໓໔໕໖໗໘໙༠༡༢༣༤༥༦༧༨༩၀၁၂၃၄၅၆၇၈၉႐႑႒႓႔႕႖႗႘႙០១២៣៤៥៦៧៨៩ ᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙ ᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏ ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙ ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙꧰꧱꧲꧳꧴꧵꧶꧷꧸꧹꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹0123456789 ?????????? ?????????? ?????????? ?????????? ?????????? ?????????? ?????????? ?????????? ?????????? ?????????? ?????????? ?????????? ????????????????????????????????????????????????????????????
LetterNumber
ᛮᛯᛰⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↀↁↂↅↆↇↈ〇〡〢〣〤〥〦〧〨〩〸〹〺ꛦꛧꛨꛩꛪꛫꛬꛭꛮꛯ ????????????????????????????????????????????????????? ?? ????? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????
OtherNumber²³¹¼½¾৴৵৶৷৸৹ ୲୳୴୵୶୷ ௰௱௲ ౸౹౺౻౼౽౾ ൰൱൲൳൴൵ ༪ ༫ ༬ ༭ ༮ ༯ ༰ ༱ ༲ ༳ ፩፪፫፬፭፮፯፰፱፲፳፴፵፶፷፸፹፺፻፼ ៰ ៱ ៲ ៳ ៴ ៵ ៶ ៷ ៸ ៹ ᧚⁰⁴⁵⁶⁷⁸⁹₀₁₂₃₄₅₆₇₈₉⅐⅑⅒⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞⅟↉①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓ ⳽ ㆒ ㆓ ㆔ ㆕ ㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㉈㉉㉊㉋㉌㉍㉎㉏㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿꠰꠱꠲꠳꠴꠵?????????????????????????????????????????????????????????????????????????????? ???? ???????? ??????? ????????? ????? ?????? ???????????????????????????????????????????????????????????????? ???????? ?? ??? ????? ???????? ???????? ??????? ?????? ??????????????????????????????? ???????????????????? ???????????????????? ?? ????????? ????????????????????????? ??????????????????????
답변
\ d는 모든 유니 코드를 검사하지만 [0-9]는이 10 자로 제한됩니다. 10 자리 숫자 인 경우 사용해야합니다. \ d , 사용하는 것이 적기 때문에 다른 것을 추천합니다.