রুবিতে একটি স্ট্রিং একটি রেজিপ্সের সাথে মেলে কিনা তা পরীক্ষা করার দ্রুততম উপায়?


100

রুবিতে কোনও স্ট্রিং নিয়মিত প্রকাশের সাথে মেলে কিনা তা পরীক্ষা করার দ্রুততম উপায় কী?

আমার সমস্যাটি হ'ল আমাকে রান্নার সময় দেওয়া একটি রেজিএক্সএক্সের সাথে মেলে এমন কোনগুলি স্ট্রিংয়ের একটি বিশাল তালিকার মাধ্যমে "egrep" করতে হবে। আমি কেবল স্ট্রিংটি রেজিএক্সপেক্টের সাথে মেলে কিনা, কোথায় তা মেলে না, বা মেলে এমন গ্রুপগুলির বিষয়বস্তু কী তা নয় about আমি আশা করি যে এই কোডটি আমার কোডটি ম্যাচিং রেজেক্সপগুলিতে ব্যয় করে এমন সময় কমাতে ব্যবহার করা যেতে পারে।

আমি সাথে regexp লোড

pattern = Regexp.new(ptx).freeze

আমি পেয়েছি যে string =~ patternতুলনায় কিছুটা দ্রুত string.match(pattern)

এমন কি আরও কৌশল বা শর্টকাট রয়েছে যা এই পরীক্ষাটি আরও দ্রুত তৈরি করতে ব্যবহার করতে পারে?


যদি আপনি মিলে যাওয়া গোষ্ঠীগুলির বিষয়বস্তু সম্পর্কে চিন্তা না করেন তবে আপনার সেগুলি কেন? আপনি রেজেক্সকে নন-ক্যাপচারিংয়ে রূপান্তর করে দ্রুত তৈরি করতে পারেন।
মার্ক টমাস

4
যেহেতু রিজেপ্স রান-টাইমে সরবরাহ করা হয়েছে, তাই আমি ধরে নিই যে এটি নিয়ন্ত্রিত নয়, সেক্ষেত্রে রেজি-এক্সপ-এর মধ্যে দলবদ্ধকরণের অভ্যন্তরীণ রেফারেন্স থাকতে পারে এবং তাই রিজেক্সেপ সংশোধন করে নন-ক্যাপচারে রূপান্তর করা ফলাফল পরিবর্তন করতে পারে (যদি না আপনি অতিরিক্তভাবে অভ্যন্তরীণ রেফারেন্সগুলি পরীক্ষা করে দেখুন, তবে সমস্যা ক্রমশ জটিল হয়ে ওঠে)। আমি এটি কৌতূহলী মনে করি = string স্ট্রিং.ম্যাচের চেয়ে দ্রুত হবে।
djconnel

এখানে রেজিএক্সপ বরফ করার সুবিধা কী?
হার্ডিক

উত্তর:


109

রুবি ২.৪.০ দিয়ে শুরু করে আপনি এটি ব্যবহার করতে পারেন RegExp#match?:

pattern.match?(string)

Regexp#match?2.4.0 এর জন্য রিলিজ নোটগুলিতে স্পষ্টভাবে কর্মক্ষমতা বর্ধিত হিসাবে তালিকাভুক্ত করা হয়েছে , কারণ এটি অন্যান্য পদ্ধতির দ্বারা সম্পাদিত অবজেক্ট বরাদ্দকে এড়িয়ে চলে Regexp#matchএবং =~:

রেজেজএক্স # ম্যাচ?
যোগ করা হয়েছে Regexp#match?, যা কোনও ব্যাক রেফারেন্স অবজেক্ট তৈরি না করে এবং $~অবজেক্ট বরাদ্দ কমাতে পরিবর্তন না করেই একটি রেজিএক্সপ্যাক ম্যাচ চালায় ।


6
পরামর্শের জন্য ধন্যবাদ। আমি মাপদণ্ডের স্ক্রিপ্টটি আপডেট করেছি এবং Regexp#match?অন্যান্য বিকল্পের চেয়ে কমপক্ষে 50% দ্রুত is
gioele

74

এটি একটি সাধারণ মানদণ্ড:

require 'benchmark'

"test123" =~ /1/
=> 4
Benchmark.measure{ 1000000.times { "test123" =~ /1/ } }
=>   0.610000   0.000000   0.610000 (  0.578133)

"test123"[/1/]
=> "1"
Benchmark.measure{ 1000000.times { "test123"[/1/] } }
=>   0.718000   0.000000   0.718000 (  0.750010)

irb(main):019:0> "test123".match(/1/)
=> #<MatchData "1">
Benchmark.measure{ 1000000.times { "test123".match(/1/) } }
=>   1.703000   0.000000   1.703000 (  1.578146)

তাই =~দ্রুত তবে এটি প্রত্যাবর্তিত মান হিসাবে কী পেতে চান তা নির্ভর করে। আপনি যদি ঠিক এটি পরীক্ষা করে দেখতে চান যে পাঠ্যটিতে একটি রেজেক্স রয়েছে বা না রয়েছে=~


4
আমি যেমন লিখেছি, আমি ইতিমধ্যে খুঁজে পেয়েছি যে বড় রেজিক্সপসে কাজ করার সময় কম নাটকীয় পারফরম্যান্স বৃদ্ধি পেয়ে এর =~চেয়ে দ্রুত match। আমি যা ভাবছি তা হ'ল যদি এই চেকটিকে আরও দ্রুততর করার কোনও অদ্ভুত উপায় আছে, সম্ভবত রেজিএক্সএক্সে কিছু অদ্ভুত পদ্ধতি ব্যবহার করে বা কিছু অদ্ভুত নির্মাণ করতে পারে।
gioele

আমি মনে করি এর বাইরে অন্য কোনও সমাধান নেই
ডুগুই

কি হবে !("test123" !~ /1/)?
ma11 she28

4
@ ম্যাটডিপিপাস্কোলে, দ্বিগুণ বিপরীতটি দ্রুত হওয়া উচিত নয়"test123" =~ /1/
ডগুই

4
/1/.match?("test123")"test123" =~ /1/এটি কেবল পাঠ্যের মধ্যে একটি রেজেক্স রয়েছে কি না তা যাচাই করা কিনা তার চেয়ে দ্রুত ।
নুরজ

42

নেট সম্পর্কে কিছু নিবন্ধ সন্ধানের পরে এটি আমি চালিয়েছি bench

re.match?(str)পূর্ববর্তী সংস্করণগুলিতে ২.৪.০ সহ বিজয়ী (@ উইক্টর-স্ট্রিবিউইউ দ্বারা প্রস্তাবিত) re =~ strদ্রুততম বলে মনে হচ্ছে, যদিও str =~ reএটি প্রায় তত দ্রুত is

#!/usr/bin/env ruby
require 'benchmark'

str = "aacaabc"
re = Regexp.new('a+b').freeze

N = 4_000_000

Benchmark.bm do |b|
    b.report("str.match re\t") { N.times { str.match re } }
    b.report("str =~ re\t")    { N.times { str =~ re } }
    b.report("str[re]  \t")    { N.times { str[re] } }
    b.report("re =~ str\t")    { N.times { re =~ str } }
    b.report("re.match str\t") { N.times { re.match str } }
    if re.respond_to?(:match?)
        b.report("re.match? str\t") { N.times { re.match? str } }
    end
end

ফলাফল এমআরআই 1.9.3-o551:

$ ./bench-re.rb  | sort -t $'\t' -k 2
       user     system      total        real
re =~ str         2.390000   0.000000   2.390000 (  2.397331)
str =~ re         2.450000   0.000000   2.450000 (  2.446893)
str[re]           2.940000   0.010000   2.950000 (  2.941666)
re.match str      3.620000   0.000000   3.620000 (  3.619922)
str.match re      4.180000   0.000000   4.180000 (  4.180083)

ফলাফল এমআরআই 2.1.5:

$ ./bench-re.rb  | sort -t $'\t' -k 2
       user     system      total        real
re =~ str         1.150000   0.000000   1.150000 (  1.144880)
str =~ re         1.160000   0.000000   1.160000 (  1.150691)
str[re]           1.330000   0.000000   1.330000 (  1.337064)
re.match str      2.250000   0.000000   2.250000 (  2.255142)
str.match re      2.270000   0.000000   2.270000 (  2.270948)

ফলাফল এমআরআই ২.৩.৩ (রেগেক্সের মিলের ক্ষেত্রে একটি রিগ্রেশন রয়েছে, মনে হয়):

$ ./bench-re.rb  | sort -t $'\t' -k 2
       user     system      total        real
re =~ str         3.540000   0.000000   3.540000 (  3.535881)
str =~ re         3.560000   0.000000   3.560000 (  3.560657)
str[re]           4.300000   0.000000   4.300000 (  4.299403)
re.match str      5.210000   0.010000   5.220000 (  5.213041)
str.match re      6.000000   0.000000   6.000000 (  6.000465)

ফলাফল এমআরআই ২.৪.০:

$ ./bench-re.rb  | sort -t $'\t' -k 2
       user     system      total        real
re.match? str     0.690000   0.010000   0.700000 (  0.682934)
re =~ str         1.040000   0.000000   1.040000 (  1.035863)
str =~ re         1.040000   0.000000   1.040000 (  1.042963)
str[re]           1.340000   0.000000   1.340000 (  1.339704)
re.match str      2.040000   0.000000   2.040000 (  2.046464)
str.match re      2.180000   0.000000   2.180000 (  2.174691)

কেবল নোট যোগ করতে, আক্ষরিক ফর্মগুলি এগুলির চেয়ে দ্রুত। যেমন /a+b/ =~ strএবং str =~ /a+b/। এটি ফাংশনগুলির মাধ্যমে পুনরাবৃত্তি করার সময়ও এটি বৈধ এবং আমি একটি ভেরিয়েবলের নিয়মিত এক্সপ্রেশন সংরক্ষণ এবং হিমাংসের চেয়ে উত্তম হিসাবে এটি যথেষ্ট বৈধ দেখতে পাচ্ছি। আমি আমার স্ক্রিপ্টটি রুবি 1.9.3p547, রুবি 2.0.0p481 এবং রুবি 2.1.4p265 দিয়ে পরীক্ষা করেছি। এটা সম্ভব যে এই উন্নতিগুলি পরবর্তী প্যাচগুলিতে করা হয়েছিল তবে এখনও পূর্ববর্তী সংস্করণগুলি / প্যাচগুলি দিয়ে এটি পরীক্ষা করার কোনও পরিকল্পনা আমার নেই।
কনসোলবক্স

আমি ভেবেছিলাম !(re !~ str)দ্রুত হতে পারে, তবে তা নয়।
ma11hew28

7

re === str(কেস তুলনা) সম্পর্কে কি ?

যেহেতু এটা সত্য বা মিথ্যা মূল্যায়ণ এবং, ম্যাচ সংরক্ষণকারী ম্যাচ সূচক এবং যে কাপড় ফিরে জন্য কোন প্রয়োজন আছে, আমি ভাবছি যদি এটি একটি আরও দ্রুত চেয়ে ম্যাচিং প্রণালী হবে =~


ঠিক আছে, আমি এটি পরীক্ষা করেছি। =~আপনার একাধিক ক্যাপচার গ্রুপ থাকলেও এটি আরও দ্রুত, তবে এটি অন্যান্য বিকল্পগুলির চেয়ে দ্রুত।

বিটিডাব্লু, ভাল কি freeze? আমি এটি থেকে কোনও পারফরম্যান্স বুস্ট পরিমাপ করতে পারিনি।


এর freezeফলাফলগুলি ফলাফলগুলিতে প্রদর্শিত হবে না কারণ এটি বেঞ্চমার্ক লুপগুলির আগে ঘটে এবং প্যাটার্নটিতে নিজেই কাজ করে।
টিন ম্যান

5

আপনার নিয়মিত প্রকাশটি কতটা জটিল তার উপর নির্ভর করে আপনি সম্ভবত সহজ স্ট্রিং স্লাইসিং ব্যবহার করতে পারেন। আমি আপনার প্রয়োগের জন্য এর কার্যকারিতা সম্পর্কে নিশ্চিত নই বা এটি আসলে কোনও গতি উন্নতি করবে কিনা।

'testsentence'['stsen']
=> 'stsen' # evaluates to true
'testsentence'['koala']
=> nil # evaluates to false

আমি স্ট্রিং স্লাইসিং ব্যবহার করতে পারি না কারণ রেজিএক্সপ্যাক রান-টাইমে সরবরাহ করা হয় এবং এর উপর আমার কোনও নিয়ন্ত্রণ নেই।
gioele

আপনি স্ট্রিং স্লাইসিং ব্যবহার করতে পারেন, কেবল কোনও স্থির-স্ট্রিং ব্যবহার করে স্লাইসিং না করে। উদ্ধৃতিগুলিতে স্ট্রিংয়ের পরিবর্তে একটি পরিবর্তনশীল ব্যবহার করুন এবং এটি এখনও কাজ করবে d
টিন ম্যান

3

আমি যা ভাবছি তা হ'ল যদি এই চেকটিকে আরও দ্রুততর করার কোনও অদ্ভুত উপায় আছে, সম্ভবত রেজিএক্সএক্সে কিছু অদ্ভুত পদ্ধতি ব্যবহার করে বা কিছু অদ্ভুত নির্মাণ করতে পারে।

রেজিএক্সএক্স ইঞ্জিনগুলি কীভাবে অনুসন্ধানগুলি প্রয়োগ করে তার মধ্যে পরিবর্তিত হয়, তবে সাধারণভাবে, গতির জন্য আপনার নিদর্শনগুলি অ্যাঙ্কর করে এবং লোভী মিলগুলি এড়ায়, বিশেষত দীর্ঘ স্ট্রিংগুলি অনুসন্ধান করার সময়।

কোনও নির্দিষ্ট ইঞ্জিন কীভাবে কাজ করে সে সম্পর্কে আপনি অবগত না হওয়া অবধি সবচেয়ে ভাল কাজটি হ'ল বেঞ্চমার্কগুলি করা এবং অ্যাঙ্করগুলি যুক্ত / সরিয়ে ফেলা, অনুসন্ধানগুলি সীমাবদ্ধ করার চেষ্টা করা, ওয়াইল্ডকার্ড বনাম সুস্পষ্ট ম্যাচগুলি ব্যবহার করা ইত্যাদি is

ফলবতী মণি দ্রুত মাপকাঠিতে জিনিসের জন্য খুবই দরকারী, কারণ এটি স্মার্ট। রুবির অন্তর্নির্মিত বেঞ্চমার্ক কোডটিও কার্যকর, যদিও আপনি সাবধানতা অবলম্বন না করে আপনাকে এমন পরীক্ষা লিখতে পারেন যা আপনাকে বোকা বানায়।

আমি স্ট্যাক ওভারফ্লোতে এখানে অনেক জবাব দুটিই ব্যবহার করেছি, যাতে আপনি আমার উত্তরগুলি সন্ধান করতে পারেন এবং দ্রুত কোড কীভাবে লিখবেন সে সম্পর্কে আপনাকে ধারণা দেওয়ার জন্য প্রচুর ছোট্ট কৌশল এবং ফলাফল দেখতে পাবেন।

সবচেয়ে বড় কথাটি মনে রাখতে হবে, ধীরগতিগুলি কোথায় ঘটে তা জানার আগে আপনার সময়কালে আপনার কোডটি অপ্টিমাইজ করা খারাপ।


0

উইক্টর স্ট্রিবিউ এবং ডুগুই উত্তরগুলি সম্পূর্ণ করতে আমি এটিকে/regex/.match?("string") তত দ্রুত বলব "string".match?(/regex/)

রুবি ২.৪.০ (10 000 000 ~ 2 সেকেন্ড)

2.4.0 > require 'benchmark'
 => true 
2.4.0 > Benchmark.measure{ 10000000.times { /^CVE-[0-9]{4}-[0-9]{4,}$/.match?("CVE-2018-1589") } }
 => #<Benchmark::Tms:0x005563da1b1c80 @label="", @real=2.2060338060000504, @cstime=0.0, @cutime=0.0, @stime=0.04000000000000001, @utime=2.17, @total=2.21> 
2.4.0 > Benchmark.measure{ 10000000.times { "CVE-2018-1589".match?(/^CVE-[0-9]{4}-[0-9]{4,}$/) } }
 => #<Benchmark::Tms:0x005563da139eb0 @label="", @real=2.260814556000696, @cstime=0.0, @cutime=0.0, @stime=0.010000000000000009, @utime=2.2500000000000004, @total=2.2600000000000007> 

রুবি ২.6.২ (100 000 000 ~ 20 সেকেন্ড)

irb(main):001:0> require 'benchmark'
=> true
irb(main):005:0> Benchmark.measure{ 100000000.times { /^CVE-[0-9]{4}-[0-9]{4,}$/.match?("CVE-2018-1589") } }
=> #<Benchmark::Tms:0x0000562bc83e3768 @label="", @real=24.60139879199778, @cstime=0.0, @cutime=0.0, @stime=0.010000999999999996, @utime=24.565644999999996, @total=24.575645999999995>
irb(main):004:0> Benchmark.measure{ 100000000.times { "CVE-2018-1589".match?(/^CVE-[0-9]{4}-[0-9]{4,}$/) } }
=> #<Benchmark::Tms:0x0000562bc846aee8 @label="", @real=24.634255946999474, @cstime=0.0, @cutime=0.0, @stime=0.010046, @utime=24.598276, @total=24.608321999999998>

দ্রষ্টব্য: সময়গুলি পরিবর্তিত হয়, কখনও কখনও /regex/.match?("string")দ্রুত এবং কখনও কখনও "string".match?(/regex/), পার্থক্যগুলি কেবলমাত্র মেশিনের ক্রিয়াকলাপের কারণে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.