【发布时间】:2011-12-09 08:35:24
【问题描述】:
是否有人能够确定包含使用的算法? Ruby中的方法?例如
"helloworld".include?("hello")
【问题讨论】:
-
你知道你可以看看the source,对吧? (然后查看 C 源代码,至少对于 String 的包含。)
标签: ruby algorithm search substring
是否有人能够确定包含使用的算法? Ruby中的方法?例如
"helloworld".include?("hello")
【问题讨论】:
标签: ruby algorithm search substring
正如 emboss 在他的回答中所说,String#include 调用 rb_str_index。该函数依次调用rb_memsearch,实现了Rabin-Karp string search algorithm,根据this post on ruby-forum.com。
【讨论】:
string[substr] 是否调用相同的函数进行搜索?我的意思是同样的算法,同样的速度。
Ruby 语言规范没有规定任何特定的算法。每个实现都可以使用他们想要的任何算法。
例如在Rubinius,String#include?调用String#find_string:
def include?(needle)
if needle.kind_of? Fixnum
needle = needle % 256
str_needle = needle.chr
else
str_needle = StringValue(needle)
end
!!find_string(str_needle, 0)
end
String#find_string 又通过string_index 原语实现:
def find_string(pattern, start)
Rubinius.primitive :string_index
raise PrimitiveFailure, "String#find_string failed"
end
string_index 原语由rubinius::String::index 函数实现:
// Rubinius.primitive :string_index
Fixnum* index(STATE, String* pattern, Fixnum* start);
Fixnum* String::index(STATE, String* pattern, Fixnum* start) {
native_int total = size();
native_int match_size = pattern->size();
if(start->to_native() < 0) {
Exception::argument_error(state, "negative start given");
}
switch(match_size) {
case 0:
return start;
case 1:
{
uint8_t* buf = byte_address();
uint8_t matcher = pattern->byte_address()[0];
for(native_int pos = start->to_native(); pos < total; pos++) {
if(buf[pos] == matcher) return Fixnum::from(pos);
}
}
return nil<Fixnum>();
default:
{
uint8_t* buf = byte_address();
uint8_t* matcher = pattern->byte_address();
uint8_t* last = buf + (total - match_size);
uint8_t* pos = buf + start->to_native();
while(pos <= last) {
// Checking *pos directly then also checking memcmp is an
// optimization. It's about 10x faster than just calling memcmp
// everytime.
if(*pos == *matcher &&
memcmp(pos, matcher, match_size) == 0) {
return Fixnum::from(pos - buf);
}
pos++;
}
}
return nil<Fixnum>();
}
}
【讨论】:
这是String#include?的实际实现:
static VALUE
rb_str_include(VALUE str, VALUE arg)
{
long i;
StringValue(arg);
i = rb_str_index(str, arg, 0);
if (i == -1) return Qfalse;
return Qtrue;
}
所以实际使用的算法可以在rb_str_index 中找到。
【讨论】:
rb_memsearch,实现Karp Rabin算法(根据this post)。