# Rb\_str\_substr is much slower than rb\_str\_subpat

**URL:** <https://www.ruby-forum.com/t/rb-str-substr-is-much-slower-than-rb-str-subpat/115133>\
**Category:** Development\
**Created:** [September 20, 2007, 10:38pm UTC](https://www.ruby-forum.com/t/rb-str-substr-is-much-slower-than-rb-str-subpat/115133 "2007-09-20T22:38:48Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![nobu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/e9c0ed/32.png) [@nobu](https://www.ruby-forum.com/u/nobu)\
**Post date:** [September 20, 2007, 10:38pm UTC](https://www.ruby-forum.com/t/rb-str-substr-is-much-slower-than-rb-str-subpat/115133/1 "2007-09-20T22:38:48Z")

</div>

e$B$J$+$@$G$9!#e(B

1.9e$B$G$O!"D9$$J8;zNs$KBP$9$ke(BString#[]e$B$,!"e(BFixnume$B$r;H$C$?$H$-$N$[$&e(B  
e$B$,e(BRegexpe$B$r;H$C$?$H$-$h$j$b!"3JCJ$KCY$/$J$C$F$$$^$9!#e(B

#! /usr/bin/ruby -Ke  
require “benchmark”  
class String  
def first; self[/\A./m]; end  
def last; self[/.\z/m]; end  
def first1; self[0]; end  
def last1; self[-1]; end  
end

[[“e$BF|K\8le(B”\*1000, 10000], [“x”\*10, 100000]].each do |str, n|  
p [str.first, str.last, str.first1, str.last1]  
Benchmark.bm(6) {|b|  
b.report(“first”) {n.times{str.first}}  
b.report("last ") {n.times{str.last}}  
b.report(“first1”) {n.times{str.first1}}  
b.report("last1 ") {n.times{str.last1}}  
}  
end

$ ruby19 -v /tmp/nobu/str.rb  
ruby 1.9.0 (2007-09-21 revision 13475) [i686-linux]  
[“e$BF|e(B”, “e$B8le(B”, “e$BF|e(B”, “e$B8le(B”]  
user system total real  
first 0.020000 0.000000 0.020000 ( 0.014829)  
last 0.160000 0.000000 0.160000 ( 0.164511)  
first1 0.580000 0.000000 0.580000 ( 0.579861)  
last1 1.160000 0.010000 1.170000 ( 1.152732)  
[“x”, “x”, “x”, “x”]  
user system total real  
first 0.150000 0.000000 0.150000 ( 0.154660)  
last 0.210000 0.000000 0.210000 ( 0.212844)  
first1 0.060000 0.000000 0.060000 ( 0.059491)  
last1 0.060000 0.000000 0.060000 ( 0.058233)

e$B$I$&$be(Bstr\_strlen()e$B$,%%H%k%M%C%/$C$]$$$G$9!#e(B

$ ./ruby -v /tmp/nobu/str.rb  
ruby 1.9.0 (2007-09-21 revision 13478) [i686-linux]  
[“e$BF|e(B”, “e$B8le(B”, “e$BF|e(B”, “e$B8le(B”]  
user system total real  
first 0.030000 0.000000 0.030000 ( 0.023918)  
last 0.200000 0.000000 0.200000 ( 0.199748)  
first1 0.010000 0.000000 0.010000 ( 0.006900)  
last1 0.080000 0.000000 0.080000 ( 0.079601)  
[“x”, “x”, “x”, “x”]  
user system total real  
first 0.160000 0.000000 0.160000 ( 0.164098)  
last 0.190000 0.000000 0.190000 ( 0.184262)  
first1 0.050000 0.000000 0.050000 ( 0.055136)  
last1 0.060000 0.000000 0.060000 ( 0.059857)

# Index: string.c

— string.c (revision 13478)  
+++ string.c (working copy)  
@@ -737,25 +737,39 @@ rb\_str\_substr(VALUE str, long beg, long  
rb\_encoding \*enc = rb\_enc\_get(str);  
VALUE str2;

- int slen = str\_strlen(str, enc);

- char \*p, \*s = RSTRING\_PTR(str), \*e = s + RSTRING\_LEN(str);

- if (beg \> slen) return Qnil;
- if (beg \< 0) {
- beg += slen;
- if (beg \< 0) return Qnil;

- if (!RSTRING\_LEN(str)) {
- len = 0;  
}

- if (beg + len \> slen) {
- len = slen - beg;

- if (beg \< 0) {
- if (len \> -beg) len = -beg;
- if (-beg \* rb\_enc\_mbmaxlen(enc) \< RSTRING\_LEN(str) / 8) {
- 

```
 beg = -beg;

```

- 

```
 while (len++ < beg && (e = rb_enc_prev_char(s, e, enc)) != 0);

```

- 

```
 p = e;

```

- 

```
 if (!p) return Qnil;

```

- 

```
 while (beg-- > 0 && (p = rb_enc_prev_char(s, p, enc)) != 0);

```

- 

```
 if (!p) return Qnil;

```

- 

```
 len = e - p;

```

- 

```
 goto sub;

```

- }
- else {
- 

```
 beg += str_strlen(str, enc);

```

- 

```
 if (beg < 0) return Qnil;

```

- }  
}

- if (len \< 0) {
- len = 0;

- else if (beg \> 0 && beg \> str\_strlen(str, enc)) {
- return Qnil;  
}  
if (len == 0) {

- str2 = rb\_str\_new5(str,0,0);

- p = 0;  
}  
else {

- char \*p = str\_nth(RSTRING\_PTR(str), RSTRING\_END(str), beg, enc);
- str2 = rb\_str\_new5(str, p, str\_offset(p, RSTRING\_END(str), len,  
enc));

- p = str\_nth(s, e, beg, enc);
- len = str\_offset(p, e, len, enc);  
}
- sub:
- str2 = rb\_str\_new5(str, p, len);  
rb\_enc\_copy(str2, str);  
OBJ\_INFECT(str2, str);

---

<div class="post-metadata">

**Author:** ![nobu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/e9c0ed/32.png) [@nobu](https://www.ruby-forum.com/u/nobu)\
**Post date:** [September 21, 2007, 10:05am UTC](https://www.ruby-forum.com/t/rb-str-substr-is-much-slower-than-rb-str-subpat/115133/2 "2007-09-21T10:05:56Z")

</div>

e$B$J$+$@$G$9!#e(B

At Fri, 21 Sep 2007 05:37:59 +0900,  
Nobuyoshi N. wrote in [ruby-dev:31806]:

> 1.9e$B$G$O!"D9$$J8;zNs$KBP$9$ke(BString#[]e$B$,!"e(BFixnume$B$r;H$C$?$H$-$N$[$&e(B  
> e$B$,e(BRegexpe$B$r;H$C$?$H$-$h$j$b!"3JCJ$KCY$/$J$C$F$$$^$9!#e(B

“-”[1,1]e$B$,e(BIndexErrore$B$K$J$C$F$7$^$C$F$$$?$N$G!"\>/!9=$@5!#e(B

# Index: string.c

— string.c (revision 13481)  
+++ string.c (working copy)  
@@ -737,25 +737,41 @@ rb\_str\_substr(VALUE str, long beg, long  
rb\_encoding \*enc = rb\_enc\_get(str);  
VALUE str2;

- int slen = str\_strlen(str, enc);

- char \*p, \*s = RSTRING\_PTR(str), \*e = s + RSTRING\_LEN(str);

- if (beg \> slen) return Qnil;
- if (beg \< 0) {
- beg += slen;
- if (beg \< 0) return Qnil;

- if (!RSTRING\_LEN(str)) {
- len = 0;  
}

- if (beg + len \> slen) {
- len = slen - beg;

- if (beg \< 0) {
- if (len \> -beg) len = -beg;
- if (-beg \* rb\_enc\_mbmaxlen(enc) \< RSTRING\_LEN(str) / 8) {
- 

```
 beg = -beg;

```

- 

```
 while (len++ < beg && (e = rb_enc_prev_char(s, e, enc)) != 0);

```

- 

```
 p = e;

```

- 

```
 if (!p) return Qnil;

```

- 

```
 while (beg-- > 0 && (p = rb_enc_prev_char(s, p, enc)) != 0);

```

- 

```
 if (!p) return Qnil;

```

- 

```
 len = e - p;

```

- 

```
 goto sub;

```

- }
- else {
- 

```
 beg += str_strlen(str, enc);

```

- 

```
 if (beg < 0) return Qnil;

```

- }  
}

- if (len \< 0) {
- len = 0;

- else if (beg \> 0 && beg \> str\_strlen(str, enc)) {
- return Qnil;  
}  
if (len == 0) {

- str2 = rb\_str\_new5(str,0,0);

- p = 0;
- }
- else if ((p = str\_nth(s, e, beg, enc)) == e) {
- len = 0;  
}  
else {

- char \*p = str\_nth(RSTRING\_PTR(str), RSTRING\_END(str), beg, enc);
- str2 = rb\_str\_new5(str, p, str\_offset(p, RSTRING\_END(str), len,  
enc));

- len = str\_offset(p, e, len, enc);  
}
- sub:
- str2 = rb\_str\_new5(str, p, len);  
rb\_enc\_copy(str2, str);  
OBJ\_INFECT(str2, str);
