2011-09-23 16 views
7

यह दो भाग का सवाल है। यह देखते हुए कि आपके पास तारों की एक सरणी है जिसे किसी चरित्र में विभाजित किया जा सकता है (उदा। '@' पर ईमेल पते या '।' पर फ़ाइल नाम) जो विभाजित चरित्र से पहले वर्णों को ढूंढने का सबसे शानदार तरीका है?रूबी स्ट्रिंग सर्च: जो तेजी से विभाजित या रेगेक्स है?

my_string.split(char)[0] 

या

my_string[/regex/] 

प्रश्न के दूसरे भाग क्या है कैसे आप एक चरित्र का पहला उदाहरण से पहले सब कुछ पाने के लिए एक regex लिख सकता हूँ है। नीचे दिए गए रेगेक्स को '।' से पहले कुछ वर्ण मिलते हैं। (क्योंकि '।' पैटर्न में नहीं है) लेकिन यह समाधान पाने के लिए मेरा हैकी तरीका था।

my_string[/[A-Za-z0-9\_-]+/] 

धन्यवाद!

+5

मुझे संदेह है कि ई-मेल पते से निपटने के दौरान एक उल्लेखनीय अंतर होगा (जब तक कि आप लाखों प्रति सेकंड संसाधित नहीं कर रहे हों ...)। लेकिन आप खुद दोनों को मापते हैं और पता नहीं लगाते? –

उत्तर

12

पहले भाग का जवाब देने का सबसे आसान तरीका हमेशा के रूप में, अपने वास्तविक डेटा के साथ बेंचमार्क करना है।

require 'benchmark' 
Benchmark.bm do |x| 
    x.report { 50000.times { a = '[email protected]'.split('@')[0] } } 
    x.report { 50000.times { a = '[email protected]'[/[^@]+/] } } 
end 

(मेरी सेटअप पर) का कहना है: उदाहरण के लिए:

 user  system  total  real 
    0.130000 0.010000 0.140000 ( 0.130946) 
    0.090000 0.000000 0.090000 ( 0.096260) 

तो regex समाधान एक छोटा सा तेजी से दिखता है, लेकिन अंतर बड़ी मुश्किल से 50 000 पुनरावृत्तियों के साथ ध्यान देने योग्य है। ओटीओएच, रेगेक्स समाधान कहता है कि आपका क्या मतलब है ("मुझे पहले @ से पहले सब कुछ दें") जबकि split समाधान आपके वांछित परिणाम को थोड़ा चौराहे में प्राप्त करता है।

split दृष्टिकोण संभवतः धीमा है क्योंकि इसे पूरे स्ट्रिंग को टुकड़ों में विभाजित करने के लिए स्कैन करना है, फिर टुकड़ों की एक सरणी बनाना है, और अंत में सरणी के पहले तत्व को निकालना और बाकी को फेंक देना; मुझे नहीं पता कि वीएम इतनी चतुर है कि यह पहचानने के लिए पर्याप्त है कि उसे सरणी बनाने की आवश्यकता नहीं है, इसलिए यह थोड़ा अनुमान लगाने का काम है।

जहां तक ​​आपके दूसरे प्रश्न का संबंध है, तुम क्या मतलब है कहते हैं:

my_string[/[^.]+/] 

तुम सब कुछ चाहते हैं इससे पहले कि पहली अवधि तो कहते हैं न कि "पहली हिस्सा है कि किया जाता है की तुलना में" एक अवधि तक सब कुछ " इन पात्रों में से (जिसमें एक अवधि शामिल नहीं होती है) "।

+0

इसके लिए धन्यवाद, मुझे नहीं पता था कि रूबी में एक बेंचमार्क टूल बनाया गया था। मेरे अपने परीक्षण में मैंने पाया कि रेगेक्स भी तेज़ है, जब तक कि पहले सबस्ट्रिंग 50 वर्णों के नीचे हो, तब तक विभाजन अलग हो जाता है। बेशक, जैसा कि बताया गया है, छोटे सेटों के साथ आप शायद ही अंतर को देखते हैं। – kreek

+1

@ क्रीक: यही कारण है कि आप नई चीजों को सीखने के लिए एसओ पर लटकाते हैं :) मुझे लगता है कि कोड में अपने इरादों को यथासंभव स्पष्ट रूप से व्यक्त करना शुरू करना सबसे अच्छा है और फिर वास्तव में कोई समस्या होने पर प्रदर्शन के बारे में चिंता करें। –

+0

@muistooshort कोई कैश प्रभाव या पेजफाल्ट नहीं है? – Benjamin

4

partitionsplit से तेज़ होगा क्योंकि यह पहले मैच के बाद जांच जारी नहीं रखेगा।

index के साथ एक नियमित slice एक regexp slice से तेज होगा।

रेगेक्सप टुकड़ा भी धीमा हो जाता है क्योंकि मैच से पहले स्ट्रिंग के हिस्से को बड़ा हो जाता है। यह ~ 10 वर्णों के बाद मूल विभाजन से धीमा हो जाता है और फिर वहां से बहुत खराब हो जाता है। यदि आपके पास + या * मैच के बिना Regexp है, तो मुझे लगता है कि यह थोड़ा बेहतर मेला है।

require 'benchmark' 
n=1000000 

def bench n,email 
    printf "\n%s %s times\n", email, n 
    Benchmark.bm do |x| 
     x.report('split ') do n.times{ email.split('@')[0] } end 
     x.report('partition') do n.times{ email.partition('@').first } end 
     x.report('slice reg') do n.times{ email[/[^@]+/] } end 
     x.report('slice ind') do n.times{ email[0,email.index('@')] } end 
    end 
end 


bench n, '[email protected]' 
bench n, '[email protected]' 
bench n, '[email protected]' 
bench n, '[email protected]' 
bench n, '[email protected]omain.com' 
bench n, 'a'*254 + '@' + 'b'*253 # rfc limits 
bench n, 'a'*1000 + '@' + 'b'*1000 # for other string processing 

परिणाम 1.9.3p484:

[email protected] 1000000 times 
     user  system  total  real 
split  0.405000 0.000000 0.405000 ( 0.410023) 
partition 0.375000 0.000000 0.375000 ( 0.368021) 
slice reg 0.359000 0.000000 0.359000 ( 0.357020) 
slice ind 0.312000 0.000000 0.312000 ( 0.309018) 

[email protected] 1000000 times 
     user  system  total  real 
split  0.421000 0.000000 0.421000 ( 0.432025) 
partition 0.374000 0.000000 0.374000 ( 0.379021) 
slice reg 0.421000 0.000000 0.421000 ( 0.411024) 
slice ind 0.312000 0.000000 0.312000 ( 0.315018) 

[email protected] 1000000 times 
     user  system  total  real 
split  0.593000 0.000000 0.593000 ( 0.589034) 
partition 0.531000 0.000000 0.531000 ( 0.529030) 
slice reg 0.764000 0.000000 0.764000 ( 0.771044) 
slice ind 0.484000 0.000000 0.484000 ( 0.478027) 

[email protected] 1000000 times 
     user  system  total  real 
split  0.483000 0.000000 0.483000 ( 0.481028) 
partition 0.390000 0.016000 0.406000 ( 0.404023) 
slice reg 0.406000 0.000000 0.406000 ( 0.411024) 
slice ind 0.312000 0.000000 0.312000 ( 0.344020) 

[email protected]omain.com 1000000 times 
     user  system  total  real 
split  0.639000 0.000000 0.639000 ( 0.646037) 
partition 0.609000 0.000000 0.609000 ( 0.596034) 
slice reg 0.764000 0.000000 0.764000 ( 0.773044) 
slice ind 0.499000 0.000000 0.499000 ( 0.491028) 

a<254>@b<253> 1000000 times 
     user  system  total  real 
split  0.952000 0.000000 0.952000 ( 0.960055) 
partition 0.733000 0.000000 0.733000 ( 0.731042) 
slice reg 3.432000 0.000000 3.432000 ( 3.429196) 
slice ind 0.624000 0.000000 0.624000 ( 0.625036) 

a<1000>@b<1000> 1000000 times 
     user  system  total  real 
split  1.888000 0.000000 1.888000 ( 1.892108) 
partition 1.170000 0.016000 1.186000 ( 1.188068) 
slice reg 12.885000 0.000000 12.885000 (12.914739) 
slice ind 1.108000 0.000000 1.108000 ( 1.097063) 

2.1.3p242 ही% मतभेदों के बारे में रखती है लेकिन regexp विभाजन जहां इसे नीचे धीमा कर देती है और भी अधिक के लिए छोड़कर, सब कुछ पर 10-30 के बारे में% तेज है ।

संबंधित मुद्दे