String#count
static VALUE
rb_str_count(int argc, VALUE *argv, VALUE str)
{
char table[TR_TABLE_SIZE];
rb_encoding *enc = 0;
VALUE del = 0, nodel = 0, tstr;
char *s, *send;
int i;
int ascompat;
size_t n = 0;
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
tstr = argv[0];
StringValue(tstr);
enc = rb_enc_check(str, tstr);
if (argc == 1) {
const char *ptstr;
if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
(ptstr = RSTRING_PTR(tstr),
ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (const unsigned char *)ptstr, (const unsigned char *)ptstr+1)) &&
!is_broken_string(str)) {
int clen;
unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
s = RSTRING_PTR(str);
if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
send = RSTRING_END(str);
while (s < send) {
if (*(unsigned char*)s++ == c) n++;
}
return SIZET2NUM(n);
}
}
tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
for (i=1; i<argc; i++) {
tstr = argv[i];
StringValue(tstr);
enc = rb_enc_check(str, tstr);
tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
}
s = RSTRING_PTR(str);
if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
send = RSTRING_END(str);
ascompat = rb_enc_asciicompat(enc);
while (s < send) {
unsigned int c;
if (ascompat && (c = *(unsigned char*)s) < 0x80) {
if (table[c]) {
n++;
}
s++;
}
else {
int clen;
c = rb_enc_codepoint_len(s, send, &clen, enc);
if (tr_find(c, table, del, nodel)) {
n++;
}
s += clen;
}
}
return SIZET2NUM(n);
}
Returns the total number of characters in self that are specified by the given selectors.
For one 1-character selector, returns the count of instances of that character:
s = 'abracadabra' s.count('a') # => 5 s.count('b') # => 2 s.count('x') # => 0 s.count('') # => 0 s = 'тест' s.count('т') # => 2 s.count('е') # => 1 s = 'よろしくお願いします' s.count('よ') # => 1 s.count('し') # => 2
For one multi-character selector, returns the count of instances for all specified characters:
s = 'abracadabra' s.count('ab') # => 7 s.count('abc') # => 8 s.count('abcd') # => 9 s.count('abcdr') # => 11 s.count('abcdrx') # => 11
Order and repetition do not matter:
s.count('ba') == s.count('ab') # => true s.count('baab') == s.count('ab') # => true
For multiple selectors, forms a single selector that is the intersection of characters in all selectors and returns the count of instances for that selector:
s = 'abcdefg' s.count('abcde', 'dcbfg') == s.count('bcd') # => true s.count('abc', 'def') == s.count('') # => true
In a character selector, three characters get special treatment:
-
A caret (
'^') functions as a negation operator for the immediately following characters:Examples = 'abracadabra' s.count('^bc') # => 8 # Count of all except 'b' and 'c'.
-
A hyphen (
'-') between two other characters defines a range of characters:Examples = 'abracadabra' s.count('a-c') # => 8 # Count of all 'a', 'b', and 'c'.
-
A backslash (
'\') acts as an escape for a caret, a hyphen, or another backslash:Examples = 'abracadabra' s.count('\^bc') # => 3 # Count of '^', 'b', and 'c'. s.count('a\-c') # => 6 # Count of 'a', '-', and 'c'. 'foo\bar\baz'.count('\\') # => 2 # Count of '\'.
These usages may be mixed:
s = 'abracadabra' s.count('a-cq-t') # => 10 # Multiple ranges. s.count('ac-d') # => 7 # Range mixed with plain characters. s.count('^a-c') # => 3 # Range mixed with negation.
For multiple selectors, all forms may be used, including negations, ranges, and escapes.
s = 'abracadabra' s.count('^abc', '^def') == s.count('^abcdef') # => true s.count('a-e', 'c-g') == s.count('cde') # => true s.count('^abc', 'c-g') == s.count('defg') # => true
Related: see Querying.