класс String
Объект String хранит и обрабатывает произвольную последовательность байтов, обычно представляющую символы. Объекты String могут быть созданы с помощью String::new или в виде литералов.
Из-за проблем с алиасингом пользователи строк должны быть осведомлены о методах, которые изменяют содержимое объекта String. Как правило, методы с именами, оканчивающимися на «!», изменяют свой получатель, а те, у которых нет «!», возвращают новый String. Однако существуют исключения, например, String#[]=.
Публичные методы класса
static VALUE
rb_str_init(int argc, VALUE *argv, VALUE str)
{
static ID keyword_ids[2];
VALUE orig, opt, venc, vcapa;
VALUE kwargs[2];
rb_encoding *enc = 0;
int n;
if (!keyword_ids[0]) {
keyword_ids[0] = rb_id_encoding();
CONST_ID(keyword_ids[1], "capacity");
}
n = rb_scan_args(argc, argv, "01:", &orig, &opt);
if (!NIL_P(opt)) {
rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
venc = kwargs[0];
vcapa = kwargs[1];
if (venc != Qundef && !NIL_P(venc)) {
enc = rb_to_encoding(venc);
}
if (vcapa != Qundef && !NIL_P(vcapa)) {
long capa = NUM2LONG(vcapa);
long len = 0;
int termlen = enc ? rb_enc_mbminlen(enc) : 1;
if (capa < STR_BUF_MIN_SIZE) {
capa = STR_BUF_MIN_SIZE;
}
if (n == 1) {
StringValue(orig);
len = RSTRING_LEN(orig);
if (capa < len) {
capa = len;
}
if (orig == str) n = 0;
}
str_modifiable(str);
if (STR_EMBED_P(str)) { /* make noembed always */
char *new_ptr = ALLOC_N(char, (size_t)capa + termlen);
memcpy(new_ptr, RSTRING(str)->as.ary, RSTRING_EMBED_LEN_MAX + 1);
RSTRING(str)->as.heap.ptr = new_ptr;
}
else if (FL_TEST(str, STR_SHARED|STR_NOFREE)) {
const size_t size = (size_t)capa + termlen;
const char *const old_ptr = RSTRING_PTR(str);
const size_t osize = RSTRING(str)->as.heap.len + TERM_LEN(str);
char *new_ptr = ALLOC_N(char, (size_t)capa + termlen);
memcpy(new_ptr, old_ptr, osize < size ? osize : size);
FL_UNSET_RAW(str, STR_SHARED);
RSTRING(str)->as.heap.ptr = new_ptr;
}
else if (STR_HEAP_SIZE(str) != (size_t)capa + termlen) {
SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char,
(size_t)capa + termlen, STR_HEAP_SIZE(str));
}
RSTRING(str)->as.heap.len = len;
TERM_FILL(&RSTRING(str)->as.heap.ptr[len], termlen);
if (n == 1) {
memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), len);
rb_enc_cr_str_exact_copy(str, orig);
}
FL_SET(str, STR_NOEMBED);
RSTRING(str)->as.heap.aux.capa = capa;
}
else if (n == 1) {
rb_str_replace(str, orig);
}
if (enc) {
rb_enc_associate(str, enc);
ENC_CODERANGE_CLEAR(str);
}
}
else if (n == 1) {
rb_str_replace(str, orig);
}
return str;
} Возвращает новую строку, являющуюся копией string.
Без аргументов возвращает пустую строку с кодировкой Encoding ASCII-8BIT:
s = String.new s # => "" s.encoding # => #<Encoding:ASCII-8BIT>
С одним аргументом String string, возвращает копию string с той же кодировкой, что и string:
s = String.new("Que veut dire \u{e7}a?")
s # => "Que veut dire \u{e7}a?"
s.encoding # => #<Encoding:UTF-8>
Литеральные строки, такие как "" или здесь-документы, всегда используют кодировку сценария, в отличие от String.new.
С ключевым аргументом encoding, возвращает копию str с указанной кодировкой:
s = String.new(encoding: 'ASCII')
s.encoding # => #<Encoding:US-ASCII>
s = String.new('foo', encoding: 'ASCII')
s.encoding # => #<Encoding:US-ASCII>
Обратите внимание, что эти варианты эквивалентны:
s0 = String.new('foo', encoding: 'ASCII')
s1 = 'foo'.force_encoding('ASCII')
s0.encoding == s1.encoding # => true
С ключевым аргументом capacity, возвращает копию str; заданный capacity может задать размер внутреннего буфера, что может повлиять на производительность:
String.new(capacity: 1) # => "" String.new(capacity: 4096) # => ""
Аргументы string, encoding, и capacity могут использоваться вместе:
String.new('hello', encoding: 'UTF-8', capacity: 25)
static VALUE
rb_str_s_try_convert(VALUE dummy, VALUE str)
{
return rb_check_string_type(str);
} Если object является объектом String, возвращает object.
В противном случае, если object отвечает на :to_str, вызывает object.to_str и возвращает результат.
Возвращает nil если object не отвечает на :to_str
Вызывает исключение, если object.to_str не возвращает объект String.
Методы публичного экземпляра
static VALUE
rb_str_format_m(VALUE str, VALUE arg)
{
VALUE tmp = rb_check_array_type(arg);
if (!NIL_P(tmp)) {
return rb_str_format(RARRAY_LENINT(tmp), RARRAY_CONST_PTR(tmp), str);
}
return rb_str_format(1, &arg, str);
} Возвращает результат форматирования object по спецификации формата self (см. Kernel#sprintf для подробностей форматирования):
"%05d" % 123 # => "00123"
Если self содержит несколько подстановок, object должно быть массивом или хешем, содержащим значения для подстановки:
"%-5s: %016x" % [ "ID", self.object_id ] # => "ID : 00002b054ec93168"
"foo = %{foo}" % {foo: 'bar'} # => "foo = bar"
"foo = %{foo}, baz = %{baz}" % {foo: 'bar', baz: 'bat'} # => "foo = bar, baz = bat"
VALUE
rb_str_times(VALUE str, VALUE times)
{
VALUE str2;
long n, len;
char *ptr2;
int termlen;
if (times == INT2FIX(1)) {
return str_duplicate(rb_cString, str);
}
if (times == INT2FIX(0)) {
str2 = str_alloc(rb_cString);
rb_enc_copy(str2, str);
return str2;
}
len = NUM2LONG(times);
if (len < 0) {
rb_raise(rb_eArgError, "negative argument");
}
if (RSTRING_LEN(str) == 1 && RSTRING_PTR(str)[0] == 0) {
str2 = str_alloc(rb_cString);
if (!STR_EMBEDDABLE_P(len, 1)) {
RSTRING(str2)->as.heap.aux.capa = len;
RSTRING(str2)->as.heap.ptr = ZALLOC_N(char, (size_t)len + 1);
STR_SET_NOEMBED(str2);
}
STR_SET_LEN(str2, len);
rb_enc_copy(str2, str);
return str2;
}
if (len && LONG_MAX/len < RSTRING_LEN(str)) {
rb_raise(rb_eArgError, "argument too big");
}
len *= RSTRING_LEN(str);
termlen = TERM_LEN(str);
str2 = str_new0(rb_cString, 0, len, termlen);
ptr2 = RSTRING_PTR(str2);
if (len) {
n = RSTRING_LEN(str);
memcpy(ptr2, RSTRING_PTR(str), n);
while (n <= len/2) {
memcpy(ptr2 + n, ptr2, n);
n *= 2;
}
memcpy(ptr2 + n, ptr2, len-n);
}
STR_SET_LEN(str2, len);
TERM_FILL(&ptr2[len], termlen);
rb_enc_cr_str_copy_for_substr(str2, str);
return str2;
} Возвращает новую строку, содержащую integer копий self:
"Ho! " * 3 # => "Ho! Ho! Ho! " "Ho! " * 0 # => ""
VALUE
rb_str_plus(VALUE str1, VALUE str2)
{
VALUE str3;
rb_encoding *enc;
char *ptr1, *ptr2, *ptr3;
long len1, len2;
int termlen;
StringValue(str2);
enc = rb_enc_check_str(str1, str2);
RSTRING_GETMEM(str1, ptr1, len1);
RSTRING_GETMEM(str2, ptr2, len2);
termlen = rb_enc_mbminlen(enc);
if (len1 > LONG_MAX - len2) {
rb_raise(rb_eArgError, "string size too big");
}
str3 = str_new0(rb_cString, 0, len1+len2, termlen);
ptr3 = RSTRING_PTR(str3);
memcpy(ptr3, ptr1, len1);
memcpy(ptr3+len1, ptr2, len2);
TERM_FILL(&ptr3[len1+len2], termlen);
ENCODING_CODERANGE_SET(str3, rb_enc_to_index(enc),
ENC_CODERANGE_AND(ENC_CODERANGE(str1), ENC_CODERANGE(str2)));
RB_GC_GUARD(str1);
RB_GC_GUARD(str2);
return str3;
} Возвращает новую строку, содержащую other_string, конкатенированную со self:
"Hello from " + self.to_s # => "Hello from main"
static VALUE
str_uplus(VALUE str)
{
if (OBJ_FROZEN(str)) {
return rb_str_dup(str);
}
else {
return str;
}
} Возвращает self, если self не заморожен.
В противном случае возвращает self.dup, который не заморожен.
static VALUE
str_uminus(VALUE str)
{
if (!BARE_STRING_P(str) && !rb_obj_frozen_p(str)) {
str = rb_str_dup(str);
}
return rb_fstring(str);
} Возвращает замороженную, возможно предварительно существующую копию строки.
Возвращенная строка будет дедуплицирована, если на ней не установлено никаких переменных экземпляра.
VALUE
rb_str_concat(VALUE str1, VALUE str2)
{
unsigned int code;
rb_encoding *enc = STR_ENC_GET(str1);
int encidx;
if (RB_INTEGER_TYPE_P(str2)) {
if (rb_num_to_uint(str2, &code) == 0) {
}
else if (FIXNUM_P(str2)) {
rb_raise(rb_eRangeError, "%ld out of char range", FIX2LONG(str2));
}
else {
rb_raise(rb_eRangeError, "bignum out of char range");
}
}
else {
return rb_str_append(str1, str2);
}
encidx = rb_enc_to_index(enc);
if (encidx == ENCINDEX_ASCII || encidx == ENCINDEX_US_ASCII) {
/* US-ASCII automatically extended to ASCII-8BIT */
char buf[1];
buf[0] = (char)code;
if (code > 0xFF) {
rb_raise(rb_eRangeError, "%u out of char range", code);
}
rb_str_cat(str1, buf, 1);
if (encidx == ENCINDEX_US_ASCII && code > 127) {
rb_enc_associate_index(str1, ENCINDEX_ASCII);
ENC_CODERANGE_SET(str1, ENC_CODERANGE_VALID);
}
}
else {
long pos = RSTRING_LEN(str1);
int cr = ENC_CODERANGE(str1);
int len;
char *buf;
switch (len = rb_enc_codelen(code, enc)) {
case ONIGERR_INVALID_CODE_POINT_VALUE:
rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
break;
case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
case 0:
rb_raise(rb_eRangeError, "%u out of char range", code);
break;
}
buf = ALLOCA_N(char, len + 1);
rb_enc_mbcput(code, buf, enc);
if (rb_enc_precise_mbclen(buf, buf + len + 1, enc) != len) {
rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
}
rb_str_resize(str1, pos+len);
memcpy(RSTRING_PTR(str1) + pos, buf, len);
if (cr == ENC_CODERANGE_7BIT && code > 127)
cr = ENC_CODERANGE_VALID;
ENC_CODERANGE_SET(str1, cr);
}
return str1;
} Возвращает новую строку, содержащую конкатенацию self и object:
s = 'foo' s << 'bar' # => "foobar"
Если object является целым числом, значение рассматривается как код символа и преобразуется в символ перед конкатенацией:
s = 'foo' s << 33 # => "foo!"
Связанно с: String#concat, который принимает несколько аргументов.
static VALUE
rb_str_cmp_m(VALUE str1, VALUE str2)
{
int result;
VALUE s = rb_check_string_type(str2);
if (NIL_P(s)) {
return rb_invcmp(str1, str2);
}
result = rb_str_cmp(str1, s);
return INT2FIX(result);
} Сравнивает self и other_string, возвращая:
-
-1, если
other_stringменьше. -
0, если два значения равны.
-
1, если
other_stringбольше. -
nil, если два значения несравнимы.
Примеры:
'foo' <=> 'foo' # => 0 'foo' <=> 'food' # => -1 'food' <=> 'foo' # => 1 'FOO' <=> 'foo' # => -1 'foo' <=> 'FOO' # => 1 'foo' <=> 1 # => nil
VALUE
rb_str_equal(VALUE str1, VALUE str2)
{
if (str1 == str2) return Qtrue;
if (!RB_TYPE_P(str2, T_STRING)) {
if (!rb_respond_to(str2, idTo_str)) {
return Qfalse;
}
return rb_equal(str2, str1);
}
return rb_str_eql_internal(str1, str2);
} Возвращает true если object имеет одинаковую длину и содержимое, что и self; false в противном случае:
s = 'foo' s == 'foo' # => true s == 'food' # => false s == 'FOO' # => false
Возвращает false если кодировки двух строк несовместимы:
"\u{e4 f6 fc}".encode("ISO-8859-1") == ("\u{c4 d6 dc}") # => false
Если object не является экземпляром String, но отвечает на to_str, тогда две строки сравниваются с помощью object.==.
Возвращает true если object имеет одинаковую длину и содержимое, что и self; false в противном случае:
s = 'foo' s == 'foo' # => true s == 'food' # => false s == 'FOO' # => false
Возвращает false если кодировки двух строк несовместимы:
"\u{e4 f6 fc}".encode("ISO-8859-1") == ("\u{c4 d6 dc}") # => false
Если object не является экземпляром String, но отвечает на to_str, тогда две строки сравниваются с помощью object.==.
static VALUE
rb_str_match(VALUE x, VALUE y)
{
switch (OBJ_BUILTIN_TYPE(y)) {
case T_STRING:
rb_raise(rb_eTypeError, "type mismatch: String given");
case T_REGEXP:
return rb_reg_match(y, x);
default:
return rb_funcall(y, idEqTilde, 1, x);
}
} Возвращает целочисленный индекс первой подстроки, соответствующей заданному regexp, или nil если соответствия не найдено:
'foo' =~ /f/ # => 0 'foo' =~ /o/ # => 1 'foo' =~ /x/ # => nil
Примечание: также обновляет глобальные переменные, связанные с регулярными выражениями.
Если заданное object не является регулярным выражением, возвращает значение, возвращаемое object =~ self.
Обратите внимание, что string =~ regexp отличается от regexp =~ string (см. Regexp#=~):
number= nil "no. 9" =~ /(?<number>\d+)/ number # => nil (not assigned) /(?<number>\d+)/ =~ "no. 9" number #=> "9"
static VALUE
rb_str_aref_m(int argc, VALUE *argv, VALUE str)
{
if (argc == 2) {
if (RB_TYPE_P(argv[0], T_REGEXP)) {
return rb_str_subpat(str, argv[0], argv[1]);
}
else {
long beg = NUM2LONG(argv[0]);
long len = NUM2LONG(argv[1]);
return rb_str_substr(str, beg, len);
}
}
rb_check_arity(argc, 1, 2);
return rb_str_aref(str, argv[0]);
} Возвращает подстроку self, заданную аргументами.
Когда задан единственный целочисленный аргумент index, возвращает подстроку длиной 1 символ, найденную в self по смещению index:
'bar'[2] # => "r"
Считает назад от конца self если index отрицательно:
'foo'[-3] # => "f"
Возвращает nil если index выходит за пределы диапазона:
'foo'[3] # => nil 'foo'[-4] # => nil
Когда заданы два целочисленных аргумента start и length, возвращает подстроку заданной length, найденную в self по смещению start:
'foo'[0, 2] # => "fo" 'foo'[0, 0] # => ""
Считает назад от конца self если start отрицательно:
'foo'[-2, 2] # => "oo"
Особый случай: возвращает новую пустую строку, если start равно длине self:
'foo'[3, 2] # => ""
Возвращает nil если start выходит за пределы диапазона:
'foo'[4, 2] # => nil 'foo'[-4, 2] # => nil
Возвращает заключительную подстроку self если length велико:
'foo'[1, 50] # => "oo"
Возвращает nil если length отрицательно:
'foo'[0, -1] # => nil
Когда задан единственный диапазон range, вычисляет значения start и length из данного range, и возвращает значения, как описано выше:
-
'foo'[0..1]эквивалентно'foo'[0, 2]. -
'foo'[0...1]эквивалентно'foo'[0, 1].
Когда задан аргумент Regexp regexp, и аргумент capture равен 0, возвращает первую найденную совпадающую подстроку в self, или nil если ничего не найдено:
'foo'[/o/] # => "o" 'foo'[/x/] # => nil s = 'hello there' s[/[aeiou](.)\1/] # => "ell" s[/[aeiou](.)\1/, 0] # => "ell"
Если аргумент capture задан и не 0, он должен быть либо целочисленным индексом группы захвата, либо именем группы захвата в виде строки или символа; вызов метода возвращает только указанную группу захвата (см. Захват регулярных выражений):
s = 'hello there' s[/[aeiou](.)\1/, 1] # => "l" s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, "non_vowel"] # => "l" s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, :vowel] # => "e"
Если задан недопустимый индекс группы захвата, возвращается nil. Если задано недопустимое имя группы захвата, генерируется IndexError.
Когда задан единственный аргумент String substring, возвращает подстроку из self если найдена, иначе nil:
'foo'['oo'] # => "oo" 'foo'['xx'] # => nil
String#slice является псевдонимом для String#[].
static VALUE
rb_str_aset_m(int argc, VALUE *argv, VALUE str)
{
if (argc == 3) {
if (RB_TYPE_P(argv[0], T_REGEXP)) {
rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
}
else {
rb_str_splice(str, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]);
}
return argv[2];
}
rb_check_arity(argc, 2, 3);
return rb_str_aset(str, argv[0], argv[1]);
} Присваивание элемента — заменяет часть или всё содержимое str. Часть строки, на которую повлияет замена, определяется по тем же критериям, что и в String#[]. Если строка замены имеет другую длину, чем заменяемый текст, строка будет соответствующим образом скорректирована. Если используемый для индексации регулярный выражение или строка не совпадает с позицией в строке, возникает IndexError. Если используется форма с регулярным выражением, второй необязательный Integer позволяет указать, какую часть совпадения заменить (эффективно используя правила индексации MatchData). Формы, принимающие Integer, вызовут IndexError, если значение выходит за пределы; форма с Range вызовет RangeError, а форма с Regexp и String — IndexError при отрицательном совпадении.
static VALUE
rb_str_is_ascii_only_p(VALUE str)
{
int cr = rb_enc_str_coderange(str);
return cr == ENC_CODERANGE_7BIT ? Qtrue : Qfalse;
} Возвращает true для строки, содержащей только символы ASCII.
"abc".force_encoding("UTF-8").ascii_only? #=> true
"abc\u{6666}".force_encoding("UTF-8").ascii_only? #=> false
static VALUE
rb_str_b(VALUE str)
{
VALUE str2 = str_alloc(rb_cString);
str_replace_shared_without_enc(str2, str);
ENC_CODERANGE_CLEAR(str2);
return str2;
} Возвращает скопированную строку с кодировкой ASCII-8BIT.
static VALUE
rb_str_bytes(VALUE str)
{
VALUE ary = WANTARRAY("bytes", RSTRING_LEN(str));
return rb_str_enumerate_bytes(str, ary);
} Возвращает массив байтов в str. Это сокращенная форма записи str.each_byte.to_a.
Если задан блок, что является устаревшей формой, он работает так же, как each_byte.
static VALUE
rb_str_bytesize(VALUE str)
{
return LONG2NUM(RSTRING_LEN(str));
} Возвращает количество байтов в self:
"\x80\u3042".bytesize # => 4 "hello".bytesize # => 5
Связанно с: String#length.
static VALUE
rb_str_byteslice(int argc, VALUE *argv, VALUE str)
{
if (argc == 2) {
long beg = NUM2LONG(argv[0]);
long end = NUM2LONG(argv[1]);
return str_byte_substr(str, beg, end, TRUE);
}
rb_check_arity(argc, 1, 2);
return str_byte_aref(str, argv[0]);
} Ссылочная работа с байтами — Если передано одно Integer, возвращается подстрока длиной в один байт в указанной позиции. Если переданы два Integer, возвращается подстрока, начинающаяся с смещения, заданного первым, и имеющая длину, заданную вторым. Если задан Range, возвращается подстрока, содержащая байты в позициях, заданных диапазоном. Во всех трёх случаях, если смещение отрицательное, оно отсчитывается от конца str. Возвращает nil если начальное смещение выходит за пределы строки, длина отрицательная или начало диапазона больше конца. Кодировка результирующей строки сохраняет исходную кодировку.
"hello".byteslice(1) #=> "e" "hello".byteslice(-1) #=> "o" "hello".byteslice(1, 2) #=> "el" "\x80\u3042".byteslice(1, 3) #=> "\u3042" "\x03\u3042\xff".byteslice(1..3) #=> "\u3042"
static VALUE
rb_str_capitalize(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
VALUE ret;
flags = check_case_options(argc, argv, flags);
enc = str_true_enc(str);
if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str;
if (flags&ONIGENC_CASE_ASCII_ONLY) {
ret = rb_str_new(0, RSTRING_LEN(str));
rb_str_ascii_casemap(str, ret, &flags, enc);
}
else {
ret = rb_str_casemap(str, &flags, enc);
}
return ret;
} Возвращает копию str с первым символом в верхнем регистре, а остальные — в нижнем.
См. String#downcase для значения options и использования с различными кодировками.
"hello".capitalize #=> "Hello" "HELLO".capitalize #=> "Hello" "123ABC".capitalize #=> "123abc"
static VALUE
rb_str_capitalize_bang(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
flags = check_case_options(argc, argv, flags);
str_modify_keep_cr(str);
enc = str_true_enc(str);
if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
if (flags&ONIGENC_CASE_ASCII_ONLY)
rb_str_ascii_casemap(str, str, &flags, enc);
else
str_shared_replace(str, rb_str_casemap(str, &flags, enc));
if (ONIGENC_CASE_MODIFIED&flags) return str;
return Qnil;
} Изменяет str, преобразуя первый символ в верхний регистр, а остальные — в нижний. Возвращает nil если изменений не было. Существует исключение для современной грузинской (mkhedruli/MTAVRULI), где результат такой же, как для String#downcase, чтобы избежать смешанного регистра.
См. String#downcase для значения options и использования с различными кодировками.
a = "hello" a.capitalize! #=> "Hello" a #=> "Hello" a.capitalize! #=> nil
static VALUE
rb_str_casecmp(VALUE str1, VALUE str2)
{
VALUE s = rb_check_string_type(str2);
if (NIL_P(s)) {
return Qnil;
}
return str_casecmp(str1, s);
} Сравнивает self и other_string, игнорируя регистр, и возвращает:
-
-1, если
other_stringменьше. -
0, если значения равны.
-
1, если
other_stringбольше. -
nil, если значения несравнимы.
Примеры:
'foo'.casecmp('foo') # => 0
'foo'.casecmp('food') # => -1
'food'.casecmp('foo') # => 1
'FOO'.casecmp('foo') # => 0
'foo'.casecmp('FOO') # => 0
'foo'.casecmp(1) # => nil
static VALUE
rb_str_casecmp_p(VALUE str1, VALUE str2)
{
VALUE s = rb_check_string_type(str2);
if (NIL_P(s)) {
return Qnil;
}
return str_casecmp_p(str1, s);
} Возвращает true если self и other_string равны после Unicode преобразования регистра, иначе false:
'foo'.casecmp?('foo') # => true
'foo'.casecmp?('food') # => false
'food'.casecmp?('foo') # => true
'FOO'.casecmp?('foo') # => true
'foo'.casecmp?('FOO') # => true
Возвращает nil, если два значения несравнимы:
'foo'.casecmp?(1) # => nil
static VALUE
rb_str_center(int argc, VALUE *argv, VALUE str)
{
return rb_str_justify(argc, argv, str, 'c');
} Центрирует str в width. Если width больше длины str, возвращает новую String длиной width с str по центру и заполненную padstr; в противном случае возвращает str.
"hello".center(4) #=> "hello" "hello".center(20) #=> " hello " "hello".center(20, '123') #=> "1231231hello12312312"
static VALUE
rb_str_chars(VALUE str)
{
VALUE ary = WANTARRAY("chars", rb_str_strlen(str));
return rb_str_enumerate_chars(str, ary);
} Возвращает массив символов в str. Это сокращенная форма записи str.each_char.to_a.
Если задан блок, что является устаревшей формой, он работает так же, как each_char.
static VALUE
rb_str_chomp(int argc, VALUE *argv, VALUE str)
{
VALUE rs = chomp_rs(argc, argv);
if (NIL_P(rs)) return str_duplicate(rb_cString, str);
return rb_str_subseq(str, 0, chompped_length(str, rs));
} Возвращает новую String с удалённым разделителем строк с конца str (если он есть). Если $/ не был изменён от значения по умолчанию разделителя строк Ruby, то chomp также удаляет символы возврата каретки (то есть удалит \n, \r, и \r\n). Если $/ является пустой строкой, он удалит все заключительные символы новой строки из строки.
"hello".chomp #=> "hello"
"hello\n".chomp #=> "hello"
"hello\r\n".chomp #=> "hello"
"hello\n\r".chomp #=> "hello\n"
"hello\r".chomp #=> "hello"
"hello \n there".chomp #=> "hello \n there"
"hello".chomp("llo") #=> "he"
"hello\r\n\r\n".chomp('') #=> "hello"
"hello\r\n\r\r\n".chomp('') #=> "hello\r\n\r"
static VALUE
rb_str_chomp_bang(int argc, VALUE *argv, VALUE str)
{
VALUE rs;
str_modifiable(str);
if (RSTRING_LEN(str) == 0) return Qnil;
rs = chomp_rs(argc, argv);
if (NIL_P(rs)) return Qnil;
return rb_str_chomp_string(str, rs);
} Изменяет str в соответствии с описанием для String#chomp, возвращая str или nil если изменений не было.
static VALUE
rb_str_chop(VALUE str)
{
return rb_str_subseq(str, 0, chopped_length(str));
} Возвращает новую String со удалённым последним символом. Если строка заканчивается на \r\n, удаляются оба символа. Применение chop к пустой строке возвращает пустую строку. String#chomp часто является более безопасной альтернативой, так как она оставляет строку неизменной, если она не заканчивается разделителем записей.
"string\r\n".chop #=> "string" "string\n\r".chop #=> "string\n" "string\n".chop #=> "string" "string".chop #=> "strin" "x".chop.chop #=> ""
static VALUE
rb_str_chop_bang(VALUE str)
{
str_modify_keep_cr(str);
if (RSTRING_LEN(str) > 0) {
long len;
len = chopped_length(str);
STR_SET_LEN(str, len);
TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
ENC_CODERANGE_CLEAR(str);
}
return str;
}
return Qnil;
} Обрабатывает str так же, как для String#chop, возвращая str или nil, если str пустая. Также см. String#chomp!.
static VALUE
rb_str_chr(VALUE str)
{
return rb_str_substr(str, 0, 1);
} Возвращает строку из одного символа в начале строки.
a = "abcde" a.chr #=> "a"
static VALUE
rb_str_clear(VALUE str)
{
str_discard(str);
STR_SET_EMBED(str);
STR_SET_EMBED_LEN(str, 0);
RSTRING_PTR(str)[0] = 0;
if (rb_enc_asciicompat(STR_ENC_GET(str)))
ENC_CODERANGE_SET(str, ENC_CODERANGE_7BIT);
else
ENC_CODERANGE_SET(str, ENC_CODERANGE_VALID);
return str;
} Очищает строку.
a = "abcde" a.clear #=> ""
static VALUE
rb_str_codepoints(VALUE str)
{
VALUE ary = WANTARRAY("codepoints", rb_str_strlen(str));
return rb_str_enumerate_codepoints(str, ary);
} Возвращает массив порядковых номеров Integer символов в str. Это сокращение для str.each_codepoint.to_a.
Если задан блок, что является устаревшей формой, работает так же, как each_codepoint.
static VALUE
rb_str_concat_multi(int argc, VALUE *argv, VALUE str)
{
str_modifiable(str);
if (argc == 1) {
return rb_str_concat(str, argv[0]);
}
else if (argc > 1) {
int i;
VALUE arg_str = rb_str_tmp_new(0);
rb_enc_copy(arg_str, str);
for (i = 0; i < argc; i++) {
rb_str_concat(arg_str, argv[i]);
}
rb_str_buf_append(str, arg_str);
}
return str;
} Возвращает новую строку, содержащую конкатенацию self и всех объектов в objects:
s = 'foo'
s.concat('bar', 'baz') # => "foobarbaz"
Для каждого данного объекта object являющегося целым числом, значение рассматривается как код символа и преобразуется в символ перед конкатенацией:
s = 'foo' s.concat(32, 'bar', 32, 'baz') # => "foo bar baz"
Связанные: String#<<, принимающий один аргумент.
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;
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 n = 0;
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 INT2NUM(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);
i = 0;
while (s < send) {
unsigned int c;
if (ascompat && (c = *(unsigned char*)s) < 0x80) {
if (table[c]) {
i++;
}
s++;
}
else {
int clen;
c = rb_enc_codepoint_len(s, send, &clen, enc);
if (tr_find(c, table, del, nodel)) {
i++;
}
s += clen;
}
}
return INT2NUM(i);
} Каждый other_str параметр определяет набор символов для подсчёта. Пересечение этих наборов определяет символы для подсчёта в str. Любой other_str начинающийся с знака возведения в степень ^ инвертируется. Последовательность c1-c2 означает все символы между c1 и c2. Обратная косая черта \ может использоваться для экранирования ^ или - и в противном случае игнорируется, если она не появляется в конце последовательности или в конце other_str.
a = "hello world" a.count "lo" #=> 5 a.count "lo", "o" #=> 2 a.count "hello", "^l" #=> 4 a.count "ej-m" #=> 4 "hello^world".count "\\^aeiou" #=> 4 "hello-world".count "a\\-eo" #=> 4 c = "hello world\\r\\n" c.count "\\" #=> 2 c.count "\\A" #=> 0 c.count "X-\\w" #=> 3
static VALUE
rb_str_crypt(VALUE str, VALUE salt)
{
#ifdef HAVE_CRYPT_R
VALUE databuf;
struct crypt_data *data;
# define CRYPT_END() ALLOCV_END(databuf)
#else
extern char *crypt(const char *, const char *);
# define CRYPT_END() (void)0
#endif
VALUE result;
const char *s, *saltp;
char *res;
#ifdef BROKEN_CRYPT
char salt_8bit_clean[3];
#endif
StringValue(salt);
mustnot_wchar(str);
mustnot_wchar(salt);
if (RSTRING_LEN(salt) < 2) {
goto short_salt;
}
s = StringValueCStr(str);
saltp = RSTRING_PTR(salt);
if (!saltp[0] || !saltp[1]) goto short_salt;
#ifdef BROKEN_CRYPT
if (!ISASCII((unsigned char)saltp[0]) || !ISASCII((unsigned char)saltp[1])) {
salt_8bit_clean[0] = saltp[0] & 0x7f;
salt_8bit_clean[1] = saltp[1] & 0x7f;
salt_8bit_clean[2] = '\0';
saltp = salt_8bit_clean;
}
#endif
#ifdef HAVE_CRYPT_R
data = ALLOCV(databuf, sizeof(struct crypt_data));
# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
data->initialized = 0;
# endif
res = crypt_r(s, saltp, data);
#else
res = crypt(s, saltp);
#endif
if (!res) {
int err = errno;
CRYPT_END();
rb_syserr_fail(err, "crypt");
}
result = rb_str_new_cstr(res);
CRYPT_END();
return result;
short_salt:
rb_raise(rb_eArgError, "salt too short (need >=2 bytes)");
UNREACHABLE_RETURN(Qundef);
} Возвращает строку, сгенерированную вызовом стандартной функции crypt(3) библиотеки с str и salt_str, в указанном порядке, в качестве аргументов. Пожалуйста, больше не используйте этот метод. Он устарел; предоставляется только для обратной совместимости со скриптами ruby более ранних дней. Плохо использовать в современных программах по нескольким причинам:
-
Поведение C's
crypt(3)зависит от ОС, на которой оно выполняется. Сгенерированная строка не обладает переносимостью данных. -
В некоторых ОС, таких как Mac OS,
crypt(3)никогда не терпит неудачу (т.е. молча приводит к неожиданным результатам). -
В некоторых ОС, таких как Mac OS,
crypt(3)не является потокобезопасным. -
Так называемое «традиционное» использование
crypt(3)очень слабо. Согласно его руководству, традиционный вывод Linux'scrypt(3)имеет только 2**56 вариантов; слишком легко взломать сегодня. И это поведение по умолчанию. -
Для повышения надёжности некоторые ОС реализуют так называемое «модульное» использование. Для его использования необходимо вручную выполнить сложную подготовку параметра
salt_str. Ошибки в формировании строки соли обычно не порождают никаких ошибок; опечатки в параметрах обычно не обнаруживаются.-
Например, во втором вызове
String#cryptв приведённом примере есть ошибка; в «round=” отсутствует «s». Однако вызов не терпит неудачи и генерируется что-то неожиданное."foo".crypt("$5$rounds=1000$salt$") # OK, proper usage "foo".crypt("$5$round=1000$salt$") # Typo not detected
-
-
Даже в «модульном» режиме некоторые функции хеширования считаются устаревшими и больше не рекомендуются; например, модуль
$1$официально заброшен своим автором: см. phk.freebsd.dk/sagas/md5crypt_eol.html . Для другого примера, модуль$3$считается полностью сломанным: см. руководство по FreeBSD. -
В некоторых ОС, таких как Mac OS, нет модульного режима. Однако, как указано выше,
crypt(3)в Mac OS никогда не терпит неудачу. Это означает, что даже если вы подготовите корректную строку соли, она генерирует традиционный DES хэш, и вы не сможете этого узнать."foo".crypt("$5$rounds=1000$salt$") # => "$5fNPQMxC5j6."
Если по какой-то причине вы не можете перейти на другие современные алгоритмы хеширования паролей, установите gem string-crypt и require 'string/crypt' для продолжения его использования.
static VALUE
rb_str_delete(int argc, VALUE *argv, VALUE str)
{
str = str_duplicate(rb_cString, str);
rb_str_delete_bang(argc, argv, str);
return str;
} Возвращает копию str со всеми символами, входящими в пересечение своих аргументов, удалёнными. Использует те же правила для построения набора символов, что и String#count.
"hello".delete "l","lo" #=> "heo" "hello".delete "lo" #=> "he" "hello".delete "aeiou", "^e" #=> "hell" "hello".delete "ej-m" #=> "ho"
static VALUE
rb_str_delete_bang(int argc, VALUE *argv, VALUE str)
{
char squeez[TR_TABLE_SIZE];
rb_encoding *enc = 0;
char *s, *send, *t;
VALUE del = 0, nodel = 0;
int modify = 0;
int i, ascompat, cr;
if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
for (i=0; i<argc; i++) {
VALUE s = argv[i];
StringValue(s);
enc = rb_enc_check(str, s);
tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
}
str_modify_keep_cr(str);
ascompat = rb_enc_asciicompat(enc);
s = t = RSTRING_PTR(str);
send = RSTRING_END(str);
cr = ascompat ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID;
while (s < send) {
unsigned int c;
int clen;
if (ascompat && (c = *(unsigned char*)s) < 0x80) {
if (squeez[c]) {
modify = 1;
}
else {
if (t != s) *t = c;
t++;
}
s++;
}
else {
c = rb_enc_codepoint_len(s, send, &clen, enc);
if (tr_find(c, squeez, del, nodel)) {
modify = 1;
}
else {
if (t != s) rb_enc_mbcput(c, t, enc);
t += clen;
if (cr == ENC_CODERANGE_7BIT) cr = ENC_CODERANGE_VALID;
}
s += clen;
}
}
TERM_FILL(t, TERM_LEN(str));
STR_SET_LEN(str, t - RSTRING_PTR(str));
ENC_CODERANGE_SET(str, cr);
if (modify) return str;
return Qnil;
} Выполняет операцию delete на месте, возвращая str или nil, если str не была изменена.
static VALUE
rb_str_delete_prefix(VALUE str, VALUE prefix)
{
long prefixlen;
prefixlen = deleted_prefix_length(str, prefix);
if (prefixlen <= 0) return str_duplicate(rb_cString, str);
return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
} Возвращает копию str с удалёнными начальными prefix.
"hello".delete_prefix("hel") #=> "lo"
"hello".delete_prefix("llo") #=> "hello"
static VALUE
rb_str_delete_prefix_bang(VALUE str, VALUE prefix)
{
long prefixlen;
str_modify_keep_cr(str);
prefixlen = deleted_prefix_length(str, prefix);
if (prefixlen <= 0) return Qnil;
return rb_str_drop_bytes(str, prefixlen);
} Удаляет начальные prefix из str, возвращая nil, если изменений не было.
"hello".delete_prefix!("hel") #=> "lo"
"hello".delete_prefix!("llo") #=> nil
static VALUE
rb_str_delete_suffix(VALUE str, VALUE suffix)
{
long suffixlen;
suffixlen = deleted_suffix_length(str, suffix);
if (suffixlen <= 0) return str_duplicate(rb_cString, str);
return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
} Возвращает копию str с удалёнными конечными suffix.
"hello".delete_suffix("llo") #=> "he"
"hello".delete_suffix("hel") #=> "hello"
static VALUE
rb_str_delete_suffix_bang(VALUE str, VALUE suffix)
{
long olen, suffixlen, len;
str_modifiable(str);
suffixlen = deleted_suffix_length(str, suffix);
if (suffixlen <= 0) return Qnil;
olen = RSTRING_LEN(str);
str_modify_keep_cr(str);
len = olen - suffixlen;
STR_SET_LEN(str, len);
TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
ENC_CODERANGE_CLEAR(str);
}
return str;
} Удаляет конечные suffix из str, возвращая nil, если изменений не было.
"hello".delete_suffix!("llo") #=> "he"
"hello".delete_suffix!("hel") #=> nil
static VALUE
rb_str_downcase(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
VALUE ret;
flags = check_case_options(argc, argv, flags);
enc = str_true_enc(str);
if (case_option_single_p(flags, enc, str)) {
ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
str_enc_copy(ret, str);
downcase_single(ret);
}
else if (flags&ONIGENC_CASE_ASCII_ONLY) {
ret = rb_str_new(0, RSTRING_LEN(str));
rb_str_ascii_casemap(str, ret, &flags, enc);
}
else {
ret = rb_str_casemap(str, &flags, enc);
}
return ret;
} Возвращает копию str, в которой все заглавные буквы заменены на строчные. Какие именно буквы заменяются и на какие другие, зависит от наличия или отсутствия параметров, а также от encoding строки.
Значение параметров options таково:
- Без опций
-
Полное отображение Unicode-регистра, подходящее для большинства языков (см. опции :turkic и :lithuanian для исключений). Зависимое от контекста отображение регистра, как описано в таблице 3-14 стандарта Unicode, в настоящее время не поддерживается.
- :ascii
-
Затрагиваются только символы ASCII-диапазона, т. е. символы «A» до «Z» и «a» до «z». Данную опцию нельзя комбинировать с другими опциями.
- :turkic
-
Полное отображение Unicode-регистра, адаптированное для тюркских языков (турецкий, азербайджанский и т. д.). Это означает, что заглавная буква I отображается в строчную букву i без точки, и так далее.
- :lithuanian
-
В настоящее время используется полное отображение Unicode-регистра. В будущем будет реализовано полное отображение Unicode-регистра, адаптированное для литовского языка (поддерживая точку в строчной букве i даже при наличии диакритического знака сверху).
- :fold
-
Доступно только в
downcaseиdowncase!. Сворачивание Unicode-регистра, которое более масштабно, чем отображение Unicode-регистра. В настоящее время данная опция не может быть объединена ни с какой другой опцией (т. е. в настоящее время нет варианта для тюркских языков).
Обратите внимание, что некоторые предположения, справедливые для преобразований регистра только в ASCII, не действуют для более общих преобразований регистра. Например, длина результата может отличаться от длины входных данных (ни в символах, ни в байтах), некоторые предположения о обратном преобразовании (например, str.downcase == str.upcase.downcase) могут не применяться, и нормализация Unicode (т. е. String#unicode_normalize) не обязательно сохраняется операциями преобразования регистра.
Преобразование/сворачивание регистра для символов, не являющихся ASCII, в настоящее время поддерживается для строк/символов UTF-8, UTF-16BE/LE, UTF-32BE/LE и ISO-8859-1~16. Поддержка будет расширена до других кодировок.
"hEllO".downcase #=> "hello"
static VALUE
rb_str_downcase_bang(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
flags = check_case_options(argc, argv, flags);
str_modify_keep_cr(str);
enc = str_true_enc(str);
if (case_option_single_p(flags, enc, str)) {
if (downcase_single(str))
flags |= ONIGENC_CASE_MODIFIED;
}
else if (flags&ONIGENC_CASE_ASCII_ONLY)
rb_str_ascii_casemap(str, str, &flags, enc);
else
str_shared_replace(str, rb_str_casemap(str, &flags, enc));
if (ONIGENC_CASE_MODIFIED&flags) return str;
return Qnil;
} Преобразует содержимое str в строчные буквы, возвращая nil , если изменений не было.
См. String#downcase для значения options и использования с различными кодировками.
VALUE
rb_str_dump(VALUE str)
{
int encidx = rb_enc_get_index(str);
rb_encoding *enc = rb_enc_from_index(encidx);
long len;
const char *p, *pend;
char *q, *qend;
VALUE result;
int u8 = (encidx == rb_utf8_encindex());
static const char nonascii_suffix[] = ".dup.force_encoding(\"%s\")";
len = 2; /* "" */
if (!rb_enc_asciicompat(enc)) {
len += strlen(nonascii_suffix) - rb_strlen_lit("%s");
len += strlen(enc->name);
}
p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
while (p < pend) {
int clen;
unsigned char c = *p++;
switch (c) {
case '"': case '\\':
case '\n': case '\r':
case '\t': case '\f':
case '\013': case '\010': case '\007': case '\033':
clen = 2;
break;
case '#':
clen = IS_EVSTR(p, pend) ? 2 : 1;
break;
default:
if (ISPRINT(c)) {
clen = 1;
}
else {
if (u8 && c > 0x7F) { /* \u notation */
int n = rb_enc_precise_mbclen(p-1, pend, enc);
if (MBCLEN_CHARFOUND_P(n)) {
unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
if (cc <= 0xFFFF)
clen = 6; /* \uXXXX */
else if (cc <= 0xFFFFF)
clen = 9; /* \u{XXXXX} */
else
clen = 10; /* \u{XXXXXX} */
p += MBCLEN_CHARFOUND_LEN(n)-1;
break;
}
}
clen = 4; /* \xNN */
}
break;
}
if (clen > LONG_MAX - len) {
rb_raise(rb_eRuntimeError, "string size too big");
}
len += clen;
}
result = rb_str_new(0, len);
p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
q = RSTRING_PTR(result); qend = q + len + 1;
*q++ = '"';
while (p < pend) {
unsigned char c = *p++;
if (c == '"' || c == '\\') {
*q++ = '\\';
*q++ = c;
}
else if (c == '#') {
if (IS_EVSTR(p, pend)) *q++ = '\\';
*q++ = '#';
}
else if (c == '\n') {
*q++ = '\\';
*q++ = 'n';
}
else if (c == '\r') {
*q++ = '\\';
*q++ = 'r';
}
else if (c == '\t') {
*q++ = '\\';
*q++ = 't';
}
else if (c == '\f') {
*q++ = '\\';
*q++ = 'f';
}
else if (c == '\013') {
*q++ = '\\';
*q++ = 'v';
}
else if (c == '\010') {
*q++ = '\\';
*q++ = 'b';
}
else if (c == '\007') {
*q++ = '\\';
*q++ = 'a';
}
else if (c == '\033') {
*q++ = '\\';
*q++ = 'e';
}
else if (ISPRINT(c)) {
*q++ = c;
}
else {
*q++ = '\\';
if (u8) {
int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
if (MBCLEN_CHARFOUND_P(n)) {
int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
p += n;
if (cc <= 0xFFFF)
snprintf(q, qend-q, "u%04X", cc); /* \uXXXX */
else
snprintf(q, qend-q, "u{%X}", cc); /* \u{XXXXX} or \u{XXXXXX} */
q += strlen(q);
continue;
}
}
snprintf(q, qend-q, "x%02X", c);
q += 3;
}
}
*q++ = '"';
*q = '\0';
if (!rb_enc_asciicompat(enc)) {
snprintf(q, qend-q, nonascii_suffix, enc->name);
encidx = rb_ascii8bit_encindex();
}
/* result from dump is ASCII */
rb_enc_associate_index(result, encidx);
ENC_CODERANGE_SET(result, ENC_CODERANGE_7BIT);
return result;
} Возвращает цитированную версию строки, в которой все непечатаемые символы заменены обозначением \xHH и все специальные символы экранированы.
Этот метод может быть использован для обратного преобразования: если полученная new_str интерпретируется с помощью eval, она произведёт исходную строку.
"hello \n ''".dump #=> "\"hello \\n ''\"" "\f\x00\xff\\\"".dump #=> "\"\\f\\x00\\xFF\\\\\\\"\""
См. также String#undump.
static VALUE
rb_str_each_byte(VALUE str)
{
RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_byte_size);
return rb_str_enumerate_bytes(str, 0);
} Передаёт каждый байт в str в заданный блок, или возвращает итератор, если блок не задан.
"hello".each_byte {|c| print c, ' ' }
выводит:
104 101 108 108 111
static VALUE
rb_str_each_char(VALUE str)
{
RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
return rb_str_enumerate_chars(str, 0);
} Передаёт каждый символ в str в заданный блок, или возвращает итератор, если блок не задан.
"hello".each_char {|c| print c, ' ' }
выводит:
h e l l o
static VALUE
rb_str_each_codepoint(VALUE str)
{
RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
return rb_str_enumerate_codepoints(str, 0);
} Передаёт Integer код каждого символа в str, также известный как codepoint при работе со строками Unicode, в заданный блок. Для кодировок, отличных от UTF-8/UTF-16(BE|LE)/UTF-32(BE|LE), значения берутся непосредственно из двоичного представления каждого символа.
Если блок не задан, вместо этого возвращается итератор.
"hello\u0639".each_codepoint {|c| print c, ' ' }
выводит:
104 101 108 108 111 1593
static VALUE
rb_str_each_grapheme_cluster(VALUE str)
{
RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_grapheme_cluster_size);
return rb_str_enumerate_grapheme_clusters(str, 0);
} Передаёт каждый кластер графем в str в заданный блок или возвращает итератор, если блок не задан. В отличие от String#each_char, этот итератор перебирает кластеры графем, определённые Приложением #29 к стандарту Unicode unicode.org/reports/tr29/
"a\u0300".each_char.to_a.size #=> 2 "a\u0300".each_grapheme_cluster.to_a.size #=> 1
static VALUE
rb_str_each_line(int argc, VALUE *argv, VALUE str)
{
RETURN_SIZED_ENUMERATOR(str, argc, argv, 0);
return rb_str_enumerate_lines(argc, argv, str, 0);
} Разделяет str с использованием указанного разделителя строк (по умолчанию `/`), передавая каждую подстроку в блок. Если разделитель имеет длину ноль, строка разбивается на абзацы, разделённые несколькими последовательными символами новой строки.
Если chomp равно true, separator будет удалён с конца каждой строки.
Если блок не задан, вместо этого возвращается итератор.
"hello\nworld".each_line {|s| p s}
# prints:
# "hello\n"
# "world"
"hello\nworld".each_line('l') {|s| p s}
# prints:
# "hel"
# "l"
# "o\nworl"
# "d"
"hello\n\n\nworld".each_line('') {|s| p s}
# prints
# "hello\n\n"
# "world"
"hello\nworld".each_line(chomp: true) {|s| p s}
# prints:
# "hello"
# "world"
"hello\nworld".each_line('l', chomp: true) {|s| p s}
# prints:
# "he"
# ""
# "o\nwor"
# "d"
static VALUE
rb_str_empty(VALUE str)
{
if (RSTRING_LEN(str) == 0)
return Qtrue;
return Qfalse;
} Возвращает true , если длина self равна нулю, false в противном случае:
"hello".empty? # => false " ".empty? # => false "".empty? # => true
static VALUE
str_encode(int argc, VALUE *argv, VALUE str)
{
VALUE newstr = str;
int encidx = str_transcode(argc, argv, &newstr);
return encoded_dup(newstr, str, encidx);
} Первый вариант возвращает копию str, преобразованную в кодировку encoding. Второй вариант возвращает копию str, преобразованную из кодировки src_encoding в dst_encoding. Последний вариант возвращает копию str, преобразованную в Encoding.default_internal.
По умолчанию, первый и второй варианты генерируют исключение Encoding::UndefinedConversionError для символов, не определённых в целевой кодировке, и Encoding::InvalidByteSequenceError для недопустимых последовательностей байтов в исходной кодировке. Последний вариант по умолчанию не генерирует исключений, а использует строки замены.
Ключевые аргументы options предоставляют подробности преобразования. Аргументы:
- :invalid
-
Если значение равно
:replace,encodeзаменяет недопустимые последовательности байтов вstrсимволом замены. По умолчанию генерируется исключениеEncoding::InvalidByteSequenceError - :undef
-
Если значение равно
:replace,encodeзаменяет символы, которые не определены в целевой кодировке, символом замены. По умолчанию генерируется исключениеEncoding::UndefinedConversionError. - :replace
-
Устанавливает строку замены на указанное значение. Строка замены по умолчанию — “uFFFD” для форм кодирования Unicode и “?” в противном случае.
- :fallback
-
Устанавливает строку замены с помощью данного объекта для неопределённого символа. Объект должен быть
Hash,Proc,Methodили объектом, имеющим метод []. Его ключ — неопределённый символ, закодированный в исходной кодировке текущего преобразователя. Его значение может быть любой кодировкой, пока оно может быть преобразовано в целевую кодировку преобразователя. - :xml
-
Значение должно быть
:textили:attr. Если значение:text,encodeзаменяет неопределённые символы их (верхнерегистровыми шестнадцатеричными) цифровыми ссылками на символы. '&', '<', и '>' преобразуются в “&”, “<”, и “>”, соответственно. Если значение:attr,encodeтакже приводит результат замены в кавычки (используя '“'), и заменяет '”' на “"”. - :cr_newline
-
Заменяет LF (“n”) на CR (“r”), если значение — true.
- :crlf_newline
-
Заменяет LF (“n”) на CRLF (“rn”), если значение — true.
- :universal_newline
-
Заменяет CRLF (“rn”) и CR (“r”) на LF (“n”), если значение — true.
static VALUE
str_encode_bang(int argc, VALUE *argv, VALUE str)
{
VALUE newstr;
int encidx;
rb_check_frozen(str);
newstr = str;
encidx = str_transcode(argc, argv, &newstr);
if (encidx < 0) return str;
if (newstr == str) {
rb_enc_associate_index(str, encidx);
return str;
}
rb_str_shared_replace(str, newstr);
return str_encode_associate(str, encidx);
} Первый вариант преобразует содержимое str из str.encoding в encoding. Второй вариант преобразует содержимое str из src_encoding в dst_encoding. Ключевые аргументы options предоставляют подробности преобразования. Подробности см. в String#encode. Возвращает строку, даже если изменений не было.
VALUE
rb_obj_encoding(VALUE obj)
{
int idx = rb_enc_get_index(obj);
if (idx < 0) {
rb_raise(rb_eTypeError, "unknown encoding");
}
return rb_enc_from_encoding_index(idx & ENC_INDEX_MASK);
} Возвращает объект Encoding, представляющий кодировку объекта obj.
static VALUE
rb_str_end_with(int argc, VALUE *argv, VALUE str)
{
int i;
char *p, *s, *e;
rb_encoding *enc;
for (i=0; i<argc; i++) {
VALUE tmp = argv[i];
StringValue(tmp);
enc = rb_enc_check(str, tmp);
if (RSTRING_LEN(str) < RSTRING_LEN(tmp)) continue;
p = RSTRING_PTR(str);
e = p + RSTRING_LEN(str);
s = e - RSTRING_LEN(tmp);
if (rb_enc_left_char_head(p, s, e, enc) != s)
continue;
if (memcmp(s, RSTRING_PTR(tmp), RSTRING_LEN(tmp)) == 0)
return Qtrue;
}
return Qfalse;
} Возвращает true, если str заканчивается одной из suffixes заданных строк.
"hello".end_with?("ello") #=> true
# returns true if one of the +suffixes+ matches.
"hello".end_with?("heaven", "ello") #=> true
"hello".end_with?("heaven", "paradise") #=> false
MJIT_FUNC_EXPORTED VALUE
rb_str_eql(VALUE str1, VALUE str2)
{
if (str1 == str2) return Qtrue;
if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;
return rb_str_eql_internal(str1, str2);
} Возвращает true, если object имеет одинаковую длину и содержимое, как self; false в противном случае:
s = 'foo'
s.eql?('foo') # => true
s.eql?('food') # => false
s.eql?('FOO') # => false
Возвращает false, если кодировки двух строк несовместимы:
"\u{e4 f6 fc}".encode("ISO-8859-1").eql?("\u{c4 d6 dc}") # => false
static VALUE
rb_str_force_encoding(VALUE str, VALUE enc)
{
str_modifiable(str);
rb_enc_associate(str, rb_to_encoding(enc));
ENC_CODERANGE_CLEAR(str);
return str;
} Изменяет кодировку на encoding и возвращает self.
VALUE
rb_str_freeze(VALUE str)
{
if (OBJ_FROZEN(str)) return str;
rb_str_resize(str, RSTRING_LEN(str));
return rb_obj_freeze(str);
} static VALUE
rb_str_getbyte(VALUE str, VALUE index)
{
long pos = NUM2LONG(index);
if (pos < 0)
pos += RSTRING_LEN(str);
if (pos < 0 || RSTRING_LEN(str) <= pos)
return Qnil;
return INT2FIX((unsigned char)RSTRING_PTR(str)[pos]);
} Возвращает index-й байт в виде целого числа.
static VALUE
rb_str_grapheme_clusters(VALUE str)
{
VALUE ary = WANTARRAY("grapheme_clusters", rb_str_strlen(str));
return rb_str_enumerate_grapheme_clusters(str, ary);
} Возвращает массив графемных кластеров в str. Это сокращение для str.each_grapheme_cluster.to_a.
Если задан блок (устаревшая форма), он работает так же, как each_grapheme_cluster.
static VALUE
rb_str_gsub(int argc, VALUE *argv, VALUE str)
{
return str_gsub(argc, argv, str, 0);
} Возвращает копию str с всеми вхождениями pattern, заменёнными на второе значение. pattern обычно является Regexp; если задано как String, любые метасимволы регулярных выражений в нём будут интерпретированы буквально, например, \d будет соответствовать обратной косой черте, за которой идёт 'd', а не цифре.
Если replacement — String, он будет заменён на совпавшее значение. Он может содержать обратные ссылки на группы захвата шаблона в форме \d, где d — номер группы, или \k<n>, где n — имя группы. Аналогично, \&, \', \`, и + соответствуют специальным переменным $&, $', $`, и $+, соответственно. (См. regexp.rdoc для подробностей.) \0 эквивалентно \&. \\ интерпретируется как экранирование, т.е. как одиночная обратная косая черта. Обратите внимание, что в пределах replacement специальные переменные совпадения, такие как $&, не будут относиться к текущему совпадению.
Если вторым аргументом является Hash, и совпавшее значение является одним из его ключей, соответствующее значение является строкой замены.
В форме с блоком текущая строка совпадения передаётся в качестве параметра, и переменные, такие как $1, $2, $`, $&, и $' будут установлены соответствующим образом. (См. regexp.rdoc для подробностей.) Значение, возвращаемое блоком, будет заменено на совпадение при каждом вызове.
Когда не задан ни блок, ни второй аргумент, возвращается Enumerator.
"hello".gsub(/[aeiou]/, '*') #=> "h*ll*"
"hello".gsub(/([aeiou])/, '<\1>') #=> "h<e>ll<o>"
"hello".gsub(/./) {|s| s.ord.to_s + ' '} #=> "104 101 108 108 111 "
"hello".gsub(/(?<foo>[aeiou])/, '{\k<foo>}') #=> "h{e}ll{o}"
'hello'.gsub(/[eo]/, 'e' => 3, 'o' => '*') #=> "h3ll*"
Обратите внимание, что строковая литерал потребляет обратные косые черты. (См. syntax/literals.rdoc для подробностей о строковых литералах.) Обратные ссылки обычно предваряются дополнительной обратной косой чертой. Например, если вы хотите написать обратную ссылку \& в replacement со строковой литералом с двойными кавычками, вам нужно написать: "..\\&..". Если вы хотите написать строку без обратной ссылки \& в replacement, вам нужно сначала экранировать обратную косую черту, чтобы этот метод не интерпретировал её как обратную ссылку, а затем вам нужно экранировать обратные косые черты ещё раз, чтобы предотвратить потребление их строковой литералом: "..\\\\&..". Вы можете использовать форму с блоком, чтобы избежать множества обратных косых черт.
static VALUE
rb_str_gsub_bang(int argc, VALUE *argv, VALUE str)
{
str_modify_keep_cr(str);
return str_gsub(argc, argv, str, 1);
} Выполняет подстановки String#gsub на месте, возвращая str или nil, если подстановок не было. Если блок и replacement не заданы, возвращается перечислитель.
static VALUE
rb_str_hash_m(VALUE str)
{
st_index_t hval = rb_str_hash(str);
return ST2FIX(hval);
} Возвращает целочисленное значение хэша для self. Значение основано на длине, содержимом и кодировке self.
static VALUE
rb_str_hex(VALUE str)
{
return rb_str_to_inum(str, 16, FALSE);
} Обрабатывает ведущие символы из str как строку шестнадцатеричных цифр (с необязательным знаком и необязательным 0x) и возвращает соответствующее число. В случае ошибки возвращается ноль.
"0x0a".hex #=> 10 "-1234".hex #=> -4660 "0".hex #=> 0 "wombat".hex #=> 0
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;
} Возвращает true, если str содержит заданную строку или символ.
"hello".include? "lo" #=> true "hello".include? "ol" #=> false "hello".include? ?h #=> true
static VALUE
rb_str_index_m(int argc, VALUE *argv, VALUE str)
{
VALUE sub;
VALUE initpos;
long pos;
if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
pos = NUM2LONG(initpos);
}
else {
pos = 0;
}
if (pos < 0) {
pos += str_strlen(str, NULL);
if (pos < 0) {
if (RB_TYPE_P(sub, T_REGEXP)) {
rb_backref_set(Qnil);
}
return Qnil;
}
}
if (RB_TYPE_P(sub, T_REGEXP)) {
if (pos > str_strlen(str, NULL))
return Qnil;
pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
rb_enc_check(str, sub), single_byte_optimizable(str));
if (rb_reg_search(sub, str, pos, 0) < 0) {
return Qnil;
} else {
VALUE match = rb_backref_get();
struct re_registers *regs = RMATCH_REGS(match);
pos = rb_str_sublen(str, BEG(0));
return LONG2NUM(pos);
}
}
else {
StringValue(sub);
pos = rb_str_index(str, sub, pos);
pos = rb_str_sublen(str, pos);
}
if (pos == -1) return Qnil;
return LONG2NUM(pos);
} Возвращает целочисленную позицию первого вхождения заданного substring, или nil если не найдено:
'foo'.index('f') # => 0
'foo'.index('o') # => 1
'foo'.index('oo') # => 1
'foo'.index('ooo') # => nil
Возвращает целочисленную позицию первого соответствия заданному Regexp regexp, или nil если не найдено:
'foo'.index(/f/) # => 0 'foo'.index(/o/) # => 1 'foo'.index(/oo/) # => 1 'foo'.index(/ooo/) # => nil
Целочисленный аргумент offset, если задан, указывает позицию в строке для начала поиска:
'foo'.index('o', 1) # => 1
'foo'.index('o', 2) # => 2
'foo'.index('o', 3) # => nil
Если offset отрицательный, отсчёт идёт от конца self:
'foo'.index('o', -1) # => 2
'foo'.index('o', -2) # => 1
'foo'.index('o', -3) # => 1
'foo'.index('o', -4) # => nil
См. также: String#rindex
VALUE
rb_str_replace(VALUE str, VALUE str2)
{
str_modifiable(str);
if (str == str2) return str;
StringValue(str2);
str_discard(str);
return str_replace(str, str2);
} Заменяет содержимое str соответствующими значениями в other_str.
s = "hello" #=> "hello" s.replace "world" #=> "world"
static VALUE
rb_str_insert(VALUE str, VALUE idx, VALUE str2)
{
long pos = NUM2LONG(idx);
if (pos == -1) {
return rb_str_append(str, str2);
}
else if (pos < 0) {
pos++;
}
rb_str_splice(str, pos, 0, str2);
return str;
} Вставляет заданную other_string в self; возвращает self.
Если целое число index положительное, вставляет other_string в позицию index:
'foo'.insert(1, 'bar') # => "fbaroo"
Если целое число index отрицательное, отсчёт идёт от конца self и вставляет other_string в позицию index+1 (то есть, после self[index]):
'foo'.insert(-2, 'bar') # => "fobaro"
VALUE
rb_str_inspect(VALUE str)
{
int encidx = ENCODING_GET(str);
rb_encoding *enc = rb_enc_from_index(encidx), *actenc;
const char *p, *pend, *prev;
char buf[CHAR_ESC_LEN + 1];
VALUE result = rb_str_buf_new(0);
rb_encoding *resenc = rb_default_internal_encoding();
int unicode_p = rb_enc_unicode_p(enc);
int asciicompat = rb_enc_asciicompat(enc);
if (resenc == NULL) resenc = rb_default_external_encoding();
if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
rb_enc_associate(result, resenc);
str_buf_cat2(result, "\"");
p = RSTRING_PTR(str); pend = RSTRING_END(str);
prev = p;
actenc = get_actual_encoding(encidx, str);
if (actenc != enc) {
enc = actenc;
if (unicode_p) unicode_p = rb_enc_unicode_p(enc);
}
while (p < pend) {
unsigned int c, cc;
int n;
n = rb_enc_precise_mbclen(p, pend, enc);
if (!MBCLEN_CHARFOUND_P(n)) {
if (p > prev) str_buf_cat(result, prev, p - prev);
n = rb_enc_mbminlen(enc);
if (pend < p + n)
n = (int)(pend - p);
while (n--) {
snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
str_buf_cat(result, buf, strlen(buf));
prev = ++p;
}
continue;
}
n = MBCLEN_CHARFOUND_LEN(n);
c = rb_enc_mbc_to_codepoint(p, pend, enc);
p += n;
if ((asciicompat || unicode_p) &&
(c == '"'|| c == '\\' ||
(c == '#' &&
p < pend &&
MBCLEN_CHARFOUND_P(rb_enc_precise_mbclen(p,pend,enc)) &&
(cc = rb_enc_codepoint(p,pend,enc),
(cc == '$' || cc == '@' || cc == '{'))))) {
if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
str_buf_cat2(result, "\\");
if (asciicompat || enc == resenc) {
prev = p - n;
continue;
}
}
switch (c) {
case '\n': cc = 'n'; break;
case '\r': cc = 'r'; break;
case '\t': cc = 't'; break;
case '\f': cc = 'f'; break;
case '\013': cc = 'v'; break;
case '\010': cc = 'b'; break;
case '\007': cc = 'a'; break;
case 033: cc = 'e'; break;
default: cc = 0; break;
}
if (cc) {
if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
buf[0] = '\\';
buf[1] = (char)cc;
str_buf_cat(result, buf, 2);
prev = p;
continue;
}
if ((enc == resenc && rb_enc_isprint(c, enc)) ||
(asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c))) {
continue;
}
else {
if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
rb_str_buf_cat_escaped_char(result, c, unicode_p);
prev = p;
continue;
}
}
if (p > prev) str_buf_cat(result, prev, p - prev);
str_buf_cat2(result, "\"");
return result;
} Возвращает печатный вид str в кавычках, со спецсимволами, экранированными.
str = "hello" str[3] = "\b" str.inspect #=> "\"hel\\bo\""
VALUE
rb_str_intern(VALUE str)
{
VALUE sym;
#if USE_SYMBOL_GC
rb_encoding *enc, *ascii;
int type;
#else
ID id;
#endif
GLOBAL_SYMBOLS_ENTER(symbols);
{
sym = lookup_str_sym_with_lock(symbols, str);
if (sym) {
// ok
}
else {
#if USE_SYMBOL_GC
enc = rb_enc_get(str);
ascii = rb_usascii_encoding();
if (enc != ascii && sym_check_asciionly(str)) {
str = rb_str_dup(str);
rb_enc_associate(str, ascii);
OBJ_FREEZE(str);
enc = ascii;
}
else {
str = rb_str_dup(str);
OBJ_FREEZE(str);
}
str = rb_fstring(str);
type = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
if (type < 0) type = ID_JUNK;
sym = dsymbol_alloc(symbols, rb_cSymbol, str, enc, type);
#else
id = intern_str(str, 0);
sym = ID2SYM(id);
#endif
}
}
GLOBAL_SYMBOLS_LEAVE();
return sym;
} Возвращает Symbol, соответствующую str, создавая символ, если он не существовал ранее. См. Symbol#id2name.
"Koala".intern #=> :Koala s = 'cat'.to_sym #=> :cat s == :cat #=> true s = '@cat'.to_sym #=> :@cat s == :@cat #=> true
Это также можно использовать для создания символов, которые нельзя представить с помощью :xxx нотации.
'cat and dog'.to_sym #=> :"cat and dog"
# File ext/nkf/lib/kconv.rb, line 264 def iseuc; Kconv.iseuc(self) end
Возвращает, является ли кодировка self EUC-JP или нет.
# File ext/nkf/lib/kconv.rb, line 276 def isjis; Kconv.isjis(self) end
Возвращает, является ли кодировка self ISO-2022-JP или нет.
# File ext/nkf/lib/kconv.rb, line 270 def issjis; Kconv.issjis(self) end
Возвращает, является ли кодировка self Shift_JIS или нет.
# File ext/nkf/lib/kconv.rb, line 282 def isutf8; Kconv.isutf8(self) end
Возвращает, является ли кодировка self UTF-8 или нет.
# File ext/nkf/lib/kconv.rb, line 205 def kconv(to_enc, from_enc=nil) from_enc = self.encoding if !from_enc && self.encoding != Encoding.list[0] Kconv::kconv(self, to_enc, from_enc) end
Преобразует self в to_enc. to_enc и from_enc задаются как константы объектов Kconv или Encoding.
VALUE
rb_str_length(VALUE str)
{
return LONG2NUM(str_strlen(str, NULL));
} Возвращает количество символов (а не байтов) в self:
"\x80\u3042".length # => 2 "hello".length # => 5
String#size — алиас для String#length.
См. также: String#bytesize.
static VALUE
rb_str_lines(int argc, VALUE *argv, VALUE str)
{
VALUE ary = WANTARRAY("lines", 0);
return rb_str_enumerate_lines(argc, argv, str, ary);
} Возвращает массив строк из str, разделённых заданным разделителем записей ($/ по умолчанию). Это сокращение для str.each_line(separator, getline_args).to_a.
Если chomp равно true, separator будет удалено с конца каждой строки.
"hello\nworld\n".lines #=> ["hello\n", "world\n"]
"hello world".lines(' ') #=> ["hello ", " ", "world"]
"hello\nworld\n".lines(chomp: true) #=> ["hello", "world"]
Если задан блок (устаревшая форма), работает так же, как each_line.
static VALUE
rb_str_ljust(int argc, VALUE *argv, VALUE str)
{
return rb_str_justify(argc, argv, str, 'l');
} Если integer больше длины str, возвращает новую String длины integer, с str, выровненной влево, и заполненной padstr; в противном случае возвращает str.
"hello".ljust(4) #=> "hello" "hello".ljust(20) #=> "hello " "hello".ljust(20, '1234') #=> "hello123412341234123"
static VALUE
rb_str_lstrip(VALUE str)
{
char *start;
long len, loffset;
RSTRING_GETMEM(str, start, len);
loffset = lstrip_offset(str, start, start+len, STR_ENC_GET(str));
if (loffset <= 0) return str_duplicate(rb_cString, str);
return rb_str_subseq(str, loffset, len - loffset);
} Возвращает копию объекта-приёмника с удалёнными начальными пробелами. См. также String#rstrip и String#strip.
Обратитесь к String#strip для определения пробелов.
" hello ".lstrip #=> "hello " "hello".lstrip #=> "hello"
static VALUE
rb_str_lstrip_bang(VALUE str)
{
rb_encoding *enc;
char *start, *s;
long olen, loffset;
str_modify_keep_cr(str);
enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
loffset = lstrip_offset(str, start, start+olen, enc);
if (loffset > 0) {
long len = olen-loffset;
s = start + loffset;
memmove(start, s, len);
STR_SET_LEN(str, len);
#if !SHARABLE_MIDDLE_SUBSTRING
TERM_FILL(start+len, rb_enc_mbminlen(enc));
#endif
return str;
}
return Qnil;
} Удаляет начальные пробельные символы из получателя. Возвращает изменённый получатель или nil , если изменений не было. См. также String#rstrip! и String#strip!.
Обратитесь к String#strip для определения пробельных символов.
" hello ".lstrip! #=> "hello " "hello ".lstrip! #=> nil "hello".lstrip! #=> nil
static VALUE
rb_str_match_m(int argc, VALUE *argv, VALUE str)
{
VALUE re, result;
if (argc < 1)
rb_check_arity(argc, 1, 2);
re = argv[0];
argv[0] = str;
result = rb_funcallv(get_pat(re), rb_intern("match"), argc, argv);
if (!NIL_P(result) && rb_block_given_p()) {
return rb_yield(result);
}
return result;
} Возвращает объект Matchdata (или nil) на основе self и заданного pattern.
Примечание: также обновляет глобальные переменные, связанные с регулярными выражениями.
-
Вычисляет
regexp, преобразовываяpattern(если это не уже Regexp).regexp = Regexp.new(pattern)
-
Вычисляет
matchdata, который будет либо объектом MatchData, либоnil(см.Regexp#match):matchdata = <tt>regexp.match(self)
Без блока возвращает вычисленный matchdata:
'foo'.match('f') # => #<MatchData "f">
'foo'.match('o') # => #<MatchData "o">
'foo'.match('x') # => nil
Если задан целочисленный аргумент offset, поиск начинается с индекса offset:
'foo'.match('f', 1) # => nil
'foo'.match('o', 1) # => #<MatchData "o">
С блоком вызывает блок с вычисленным matchdata и возвращает значение, возвращаемое блоком:
'foo'.match(/o/) {|matchdata| matchdata } # => #<MatchData "o">
'foo'.match(/x/) {|matchdata| matchdata } # => nil
'foo'.match(/f/, 1) {|matchdata| matchdata } # => nil
static VALUE
rb_str_match_m_p(int argc, VALUE *argv, VALUE str)
{
VALUE re;
rb_check_arity(argc, 1, 2);
re = get_pat(argv[0]);
return rb_reg_match_p(re, str, argc > 1 ? NUM2LONG(argv[1]) : 0);
} Возвращает true или false в зависимости от того, найдено ли совпадение для self и pattern.
Примечание: не обновляет глобальные переменные, связанные с регулярными выражениями.
Вычисляет regexp, преобразовывая pattern (если это не уже Regexp).
regexp = Regexp.new(pattern)
Возвращает true , если self+.match(regexp) возвращает объект Matchdata, false в противном случае:
'foo'.match?(/o/) # => true
'foo'.match?('o') # => true
'foo'.match?(/x/) # => false
Если задан целочисленный аргумент offset, поиск начинается с индекса offset:
'foo'.match?('f', 1) # => false
'foo'.match?('o', 1) # => true
Возвращает преемник self. Преемник вычисляется путём инкрементирования символов.
Первый символ, который будет инкрементирован, — это самый правый буквенно-цифровой символ или, если таковых нет, самый правый символ:
'THX1138'.succ # => "THX1139" '<<koala>>'.succ # => "<<koalb>>" '***'.succ # => '**+'
Преемник цифры — это другая цифра, «переносящая» в следующий слева символ при «переполнении» от 9 до 0 и добавляющая другую цифру при необходимости:
'00'.succ # => "01" '09'.succ # => "10" '99'.succ # => "100"
Преемник буквы — это другая буква того же регистра, переходящая к следующему слева символу при переполнении и добавляющая другую букву того же регистра при необходимости:
'aa'.succ # => "ab" 'az'.succ # => "ba" 'zz'.succ # => "aaa" 'AA'.succ # => "AB" 'AZ'.succ # => "BA" 'ZZ'.succ # => "AAA"
Преемник не буквенно-цифрового символа — это следующий символ в порядке сортировки базового набора символов, переносящий в следующий слева символ при переполнении и добавляющий другой символ при необходимости:
s = 0.chr * 3 s # => "\x00\x00\x00" s.succ # => "\x00\x00\x01" s = 255.chr * 3 s # => "\xFF\xFF\xFF" s.succ # => "\x01\x00\x00\x00"
Перенос может происходить между и среди смесей буквенно-цифровых символов:
s = 'zz99zz99' s.succ # => "aaa00aa00" s = '99zz99zz' s.succ # => "100aa00aa"
Преемник пустой строки — это новая пустая строка:
''.succ # => ""
String#next является псевдонимом для String#succ.
Эквивалентно String#succ, но изменяет self на месте; возвращает self.
String#next! является псевдонимом для String#succ!.
static VALUE
rb_str_oct(VALUE str)
{
return rb_str_to_inum(str, -8, FALSE);
} Обрабатывает ведущие символы str как строку восьмеричных цифр (с необязательным знаком) и возвращает соответствующее число. Возвращает 0, если преобразование не выполнено.
"123".oct #=> 83 "-377".oct #=> -255 "bad".oct #=> 0 "0377bad".oct #=> 255
Если str начинается с 0, указатели радикса учитываются. См. Kernel#Integer.
static VALUE
rb_str_ord(VALUE s)
{
unsigned int c;
c = rb_enc_codepoint(RSTRING_PTR(s), RSTRING_END(s), STR_ENC_GET(s));
return UINT2NUM(c);
} Возвращает Integer порядковый номер символьной строки длиной в один символ.
"a".ord #=> 97
static VALUE
rb_str_partition(VALUE str, VALUE sep)
{
long pos;
sep = get_pat_quoted(sep, 0);
if (RB_TYPE_P(sep, T_REGEXP)) {
if (rb_reg_search(sep, str, 0, 0) < 0) {
goto failed;
}
VALUE match = rb_backref_get();
struct re_registers *regs = RMATCH_REGS(match);
pos = BEG(0);
sep = rb_str_subseq(str, pos, END(0) - pos);
}
else {
pos = rb_str_index(str, sep, 0);
if (pos < 0) goto failed;
}
return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
sep,
rb_str_subseq(str, pos+RSTRING_LEN(sep),
RSTRING_LEN(str)-pos-RSTRING_LEN(sep)));
failed:
return rb_ary_new3(3, str_duplicate(rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
} Ищет sep или шаблон (regexp) в строке и возвращает часть перед ним, совпадение и часть после него. Если не найдено, возвращает две пустые строки и str.
"hello".partition("l") #=> ["he", "l", "lo"]
"hello".partition("x") #=> ["hello", "", ""]
"hello".partition(/.l/) #=> ["h", "el", "lo"]
static VALUE
rb_str_prepend_multi(int argc, VALUE *argv, VALUE str)
{
str_modifiable(str);
if (argc == 1) {
rb_str_update(str, 0L, 0L, argv[0]);
}
else if (argc > 1) {
int i;
VALUE arg_str = rb_str_tmp_new(0);
rb_enc_copy(arg_str, str);
for (i = 0; i < argc; i++) {
rb_str_append(arg_str, argv[i]);
}
rb_str_update(str, 0L, 0L, arg_str);
}
return str;
} Возвращает новую строку, содержащую конкатенацию всех заданных other_strings и self:
s = 'foo'
s.prepend('bar', 'baz') # => "barbazfoo"
Связанные функции: String#concat.
Заменяет содержимое str соответствующими значениями в other_str.
s = "hello" #=> "hello" s.replace "world" #=> "world"
static VALUE
rb_str_reverse(VALUE str)
{
rb_encoding *enc;
VALUE rev;
char *s, *e, *p;
int cr;
if (RSTRING_LEN(str) <= 1) return str_duplicate(rb_cString, str);
enc = STR_ENC_GET(str);
rev = rb_str_new(0, RSTRING_LEN(str));
s = RSTRING_PTR(str); e = RSTRING_END(str);
p = RSTRING_END(rev);
cr = ENC_CODERANGE(str);
if (RSTRING_LEN(str) > 1) {
if (single_byte_optimizable(str)) {
while (s < e) {
*--p = *s++;
}
}
else if (cr == ENC_CODERANGE_VALID) {
while (s < e) {
int clen = rb_enc_fast_mbclen(s, e, enc);
p -= clen;
memcpy(p, s, clen);
s += clen;
}
}
else {
cr = rb_enc_asciicompat(enc) ?
ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID;
while (s < e) {
int clen = rb_enc_mbclen(s, e, enc);
if (clen > 1 || (*s & 0x80)) cr = ENC_CODERANGE_UNKNOWN;
p -= clen;
memcpy(p, s, clen);
s += clen;
}
}
}
STR_SET_LEN(rev, RSTRING_LEN(str));
str_enc_copy(rev, str);
ENC_CODERANGE_SET(rev, cr);
return rev;
} Возвращает новую строку с символами из str в обратном порядке.
"stressed".reverse #=> "desserts"
static VALUE
rb_str_reverse_bang(VALUE str)
{
if (RSTRING_LEN(str) > 1) {
if (single_byte_optimizable(str)) {
char *s, *e, c;
str_modify_keep_cr(str);
s = RSTRING_PTR(str);
e = RSTRING_END(str) - 1;
while (s < e) {
c = *s;
*s++ = *e;
*e-- = c;
}
}
else {
str_shared_replace(str, rb_str_reverse(str));
}
}
else {
str_modify_keep_cr(str);
}
return str;
} Изменяет str на месте.
static VALUE
rb_str_rindex_m(int argc, VALUE *argv, VALUE str)
{
VALUE sub;
VALUE vpos;
rb_encoding *enc = STR_ENC_GET(str);
long pos, len = str_strlen(str, enc); /* str's enc */
if (rb_scan_args(argc, argv, "11", &sub, &vpos) == 2) {
pos = NUM2LONG(vpos);
if (pos < 0) {
pos += len;
if (pos < 0) {
if (RB_TYPE_P(sub, T_REGEXP)) {
rb_backref_set(Qnil);
}
return Qnil;
}
}
if (pos > len) pos = len;
}
else {
pos = len;
}
if (RB_TYPE_P(sub, T_REGEXP)) {
/* enc = rb_get_check(str, sub); */
pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
enc, single_byte_optimizable(str));
if (rb_reg_search(sub, str, pos, 1) >= 0) {
VALUE match = rb_backref_get();
struct re_registers *regs = RMATCH_REGS(match);
pos = rb_str_sublen(str, BEG(0));
return LONG2NUM(pos);
}
}
else {
StringValue(sub);
pos = rb_str_rindex(str, sub, pos);
if (pos >= 0) return LONG2NUM(pos);
}
return Qnil;
} Возвращает целочисленный индекс последнего вхождения заданного substring, или nil если не найдено:
'foo'.rindex('f') # => 0
'foo'.rindex('o') # => 2
'foo'.rindex('oo') # => 1
'foo'.rindex('ooo') # => nil
Возвращает целочисленный индекс последнего совпадения с заданным Regexp regexp, или nil если не найдено:
'foo'.rindex(/f/) # => 0 'foo'.rindex(/o/) # => 2 'foo'.rindex(/oo/) # => 1 'foo'.rindex(/ooo/) # => nil
Целочисленный аргумент offset, если задан и неотрицателен, определяет максимальную стартовую позицию в
string to _end_ the search:
'foo'.rindex('o', 0) # => nil
'foo'.rindex('o', 1) # => 1
'foo'.rindex('o', 2) # => 2
'foo'.rindex('o', 3) # => 2
Если offset является отрицательным целым числом, максимальная стартовая позиция в строке для завершения поиска — это сумма длины строки и offset:
'foo'.rindex('o', -1) # => 2
'foo'.rindex('o', -2) # => 1
'foo'.rindex('o', -3) # => nil
'foo'.rindex('o', -4) # => nil
Связанные функции: String#index
static VALUE
rb_str_rjust(int argc, VALUE *argv, VALUE str)
{
return rb_str_justify(argc, argv, str, 'r');
} Если integer больше длины str, возвращает новую String длиной integer с str, выровненной вправо и заполненной padstr; в противном случае возвращает str.
"hello".rjust(4) #=> "hello" "hello".rjust(20) #=> " hello" "hello".rjust(20, '1234') #=> "123412341234123hello"
static VALUE
rb_str_rpartition(VALUE str, VALUE sep)
{
long pos = RSTRING_LEN(str);
sep = get_pat_quoted(sep, 0);
if (RB_TYPE_P(sep, T_REGEXP)) {
if (rb_reg_search(sep, str, pos, 1) < 0) {
goto failed;
}
VALUE match = rb_backref_get();
struct re_registers *regs = RMATCH_REGS(match);
pos = BEG(0);
sep = rb_str_subseq(str, pos, END(0) - pos);
}
else {
pos = rb_str_sublen(str, pos);
pos = rb_str_rindex(str, sep, pos);
if(pos < 0) {
goto failed;
}
pos = rb_str_offset(str, pos);
}
return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
sep,
rb_str_subseq(str, pos+RSTRING_LEN(sep),
RSTRING_LEN(str)-pos-RSTRING_LEN(sep)));
failed:
return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(rb_cString, str));
} Ищет sep или шаблон (regexp) в строке с конца строки и возвращает часть перед ним, совпадение и часть после него. Если не найдено, возвращает две пустые строки и str.
"hello".rpartition("l") #=> ["hel", "l", "o"]
"hello".rpartition("x") #=> ["", "", "hello"]
"hello".rpartition(/.l/) #=> ["he", "ll", "o"]
static VALUE
rb_str_rstrip(VALUE str)
{
rb_encoding *enc;
char *start;
long olen, roffset;
enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
roffset = rstrip_offset(str, start, start+olen, enc);
if (roffset <= 0) return str_duplicate(rb_cString, str);
return rb_str_subseq(str, 0, olen-roffset);
} Возвращает копию получателя с удалёнными пробелами в конце. См. также String#lstrip и String#strip.
Обратитесь к String#strip для определения пробелов.
" hello ".rstrip #=> " hello" "hello".rstrip #=> "hello"
static VALUE
rb_str_rstrip_bang(VALUE str)
{
rb_encoding *enc;
char *start;
long olen, roffset;
str_modify_keep_cr(str);
enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
roffset = rstrip_offset(str, start, start+olen, enc);
if (roffset > 0) {
long len = olen - roffset;
STR_SET_LEN(str, len);
#if !SHARABLE_MIDDLE_SUBSTRING
TERM_FILL(start+len, rb_enc_mbminlen(enc));
#endif
return str;
}
return Qnil;
} Удаляет пробелы в конце получателя. Возвращает изменённый получатель или nil если изменений не было. См. также String#lstrip! и String#strip!.
Обратитесь к String#strip для определения пробелов.
" hello ".rstrip! #=> " hello" " hello".rstrip! #=> nil "hello".rstrip! #=> nil
static VALUE
rb_str_scan(VALUE str, VALUE pat)
{
VALUE result;
long start = 0;
long last = -1, prev = 0;
char *p = RSTRING_PTR(str); long len = RSTRING_LEN(str);
pat = get_pat_quoted(pat, 1);
mustnot_broken(str);
if (!rb_block_given_p()) {
VALUE ary = rb_ary_new();
while (!NIL_P(result = scan_once(str, pat, &start, 0))) {
last = prev;
prev = start;
rb_ary_push(ary, result);
}
if (last >= 0) rb_pat_search(pat, str, last, 1);
else rb_backref_set(Qnil);
return ary;
}
while (!NIL_P(result = scan_once(str, pat, &start, 1))) {
last = prev;
prev = start;
rb_yield(result);
str_mod_check(str, p, len);
}
if (last >= 0) rb_pat_search(pat, str, last, 1);
return str;
} В обоих формах итерация по str, сопоставляя шаблон (который может быть Regexp или String). Для каждого совпадения генерируется результат, который либо добавляется в массив результатов, либо передаётся в блок. Если шаблон не содержит групп, каждый отдельный результат состоит из сопоставленной строки, $&. Если шаблон содержит группы, каждый отдельный результат сам по себе является массивом, содержащим по одному элементу на группу.
a = "cruel world" a.scan(/\w+/) #=> ["cruel", "world"] a.scan(/.../) #=> ["cru", "el ", "wor"] a.scan(/(...)/) #=> [["cru"], ["el "], ["wor"]] a.scan(/(..)(..)/) #=> [["cr", "ue"], ["l ", "wo"]]
А вот и форма с блоком:
a.scan(/\w+/) {|w| print "<<#{w}>> " }
print "\n"
a.scan(/(.)(.)/) {|x,y| print y, x }
print "\n"
выводит:
<<cruel>> <<world>> rceu lowlr
static VALUE
str_scrub(int argc, VALUE *argv, VALUE str)
{
VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
VALUE new = rb_str_scrub(str, repl);
return NIL_P(new) ? str_duplicate(rb_cString, str): new;
} Если в строке некорректная последовательность байтов, то заменяет некорректные байты заданным символом замены, в противном случае возвращает self. Если задан блок, заменяет некорректные байты возвращаемым значением блока.
"abc\u3042\x81".scrub #=> "abc\u3042\uFFFD"
"abc\u3042\x81".scrub("*") #=> "abc\u3042*"
"abc\u3042\xE3\x80".scrub{|bytes| '<'+bytes.unpack('H*')[0]+'>' } #=> "abc\u3042<e380>"
static VALUE
str_scrub_bang(int argc, VALUE *argv, VALUE str)
{
VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
VALUE new = rb_str_scrub(str, repl);
if (!NIL_P(new)) rb_str_replace(str, new);
return str;
} Если в строке некорректная последовательность байтов, то заменяет некорректные байты заданным символом замены, в противном случае возвращает self. Если задан блок, заменяет некорректные байты возвращаемым значением блока.
"abc\u3042\x81".scrub! #=> "abc\u3042\uFFFD"
"abc\u3042\x81".scrub!("*") #=> "abc\u3042*"
"abc\u3042\xE3\x80".scrub!{|bytes| '<'+bytes.unpack('H*')[0]+'>' } #=> "abc\u3042<e380>"
static VALUE
rb_str_setbyte(VALUE str, VALUE index, VALUE value)
{
long pos = NUM2LONG(index);
long len = RSTRING_LEN(str);
char *head, *left = 0;
unsigned char *ptr;
rb_encoding *enc;
int cr = ENC_CODERANGE_UNKNOWN, width, nlen;
if (pos < -len || len <= pos)
rb_raise(rb_eIndexError, "index %ld out of string", pos);
if (pos < 0)
pos += len;
VALUE v = rb_to_int(value);
VALUE w = rb_int_and(v, INT2FIX(0xff));
unsigned char byte = NUM2INT(w) & 0xFF;
if (!str_independent(str))
str_make_independent(str);
enc = STR_ENC_GET(str);
head = RSTRING_PTR(str);
ptr = (unsigned char *)&head[pos];
if (!STR_EMBED_P(str)) {
cr = ENC_CODERANGE(str);
switch (cr) {
case ENC_CODERANGE_7BIT:
left = (char *)ptr;
*ptr = byte;
if (ISASCII(byte)) goto end;
nlen = rb_enc_precise_mbclen(left, head+len, enc);
if (!MBCLEN_CHARFOUND_P(nlen))
ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
else
ENC_CODERANGE_SET(str, ENC_CODERANGE_VALID);
goto end;
case ENC_CODERANGE_VALID:
left = rb_enc_left_char_head(head, ptr, head+len, enc);
width = rb_enc_precise_mbclen(left, head+len, enc);
*ptr = byte;
nlen = rb_enc_precise_mbclen(left, head+len, enc);
if (!MBCLEN_CHARFOUND_P(nlen))
ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
else if (MBCLEN_CHARFOUND_LEN(nlen) != width || ISASCII(byte))
ENC_CODERANGE_CLEAR(str);
goto end;
}
}
ENC_CODERANGE_CLEAR(str);
*ptr = byte;
end:
return value;
} изменяет index-ый байт на integer.
# File lib/shellwords.rb, line 224 def shellescape Shellwords.escape(self) end
Экранирует str таким образом, чтобы его можно было безопасно использовать в командной строке оболочки Bourne.
См. Shellwords.shellescape для подробностей.
# File lib/shellwords.rb, line 213 def shellsplit Shellwords.split(self) end
Разделяет str на массив токенов так же, как это делает оболочка Bourne UNIX.
См. Shellwords.shellsplit для подробностей.
Возвращает количество символов (а не байтов) в self:
"\x80\u3042".length # => 2 "hello".length # => 5
String#size является псевдонимом для String#length.
Связанные: String#bytesize.
Возвращает подстроку self, указанную аргументами.
Когда указан единственный целочисленный аргумент index, возвращает подстроку длиной в 1 символ, расположенную в self по смещению index:
'bar'[2] # => "r"
Счётчик идёт назад от конца self если index отрицателен:
'foo'[-3] # => "f"
Возвращает nil если index выходит за пределы диапазона:
'foo'[3] # => nil 'foo'[-4] # => nil
Когда указаны два целочисленных аргумента start и length, возвращает подстроку заданной length длины, расположенную в self по смещению start:
'foo'[0, 2] # => "fo" 'foo'[0, 0] # => ""
Счётчик идёт назад от конца self если start отрицателен:
'foo'[-2, 2] # => "oo"
Специальный случай: возвращает новую пустую строку, если start равно длине self:
'foo'[3, 2] # => ""
Возвращает nil если start выходит за пределы диапазона:
'foo'[4, 2] # => nil 'foo'[-4, 2] # => nil
Возвращает заключительную подстроку self если length большое:
'foo'[1, 50] # => "oo"
Возвращает nil если length отрицательно:
'foo'[0, -1] # => nil
Когда указан единственный диапазон range, вычисляет значения start и length из заданного range, и возвращает значения, как указано выше:
-
'foo'[0..1]эквивалентно'foo'[0, 2]. -
'foo'[0...1]эквивалентно'foo'[0, 1].
Когда в качестве аргумента указан Regexp regexp, а аргумент capture равен 0, возвращает первую найденную сопоставляющую подстроку в self, или nil если не найдено:
'foo'[/o/] # => "o" 'foo'[/x/] # => nil s = 'hello there' s[/[aeiou](.)\1/] # => "ell" s[/[aeiou](.)\1/, 0] # => "ell"
Если задан аргумент capture и он не 0, он должен быть либо индексом целочисленной группы захвата, либо строкой или символом имени группы захвата; метод возвращает только указанную группу (см. Regexp Capturing):
s = 'hello there' s[/[aeiou](.)\1/, 1] # => "l" s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, "non_vowel"] # => "l" s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, :vowel] # => "e"
Если задан недопустимый индекс группы захвата, возвращается nil. Если задано недопустимое имя группы захвата, вызывается исключение IndexError.
Когда в качестве единственного аргумента указана строка substring, возвращает подстроку, начиная с self, если найдена, в противном случае nil:
'foo'['oo'] # => "oo" 'foo'['xx'] # => nil
String#slice является псевдонимом для String#[].
static VALUE
rb_str_slice_bang(int argc, VALUE *argv, VALUE str)
{
VALUE result = Qnil;
VALUE indx;
long beg, len = 1;
char *p;
rb_check_arity(argc, 1, 2);
str_modify_keep_cr(str);
indx = argv[0];
if (RB_TYPE_P(indx, T_REGEXP)) {
if (rb_reg_search(indx, str, 0, 0) < 0) return Qnil;
VALUE match = rb_backref_get();
struct re_registers *regs = RMATCH_REGS(match);
int nth = 0;
if (argc > 1 && (nth = rb_reg_backref_number(match, argv[1])) < 0) {
if ((nth += regs->num_regs) <= 0) return Qnil;
}
else if (nth >= regs->num_regs) return Qnil;
beg = BEG(nth);
len = END(nth) - beg;
goto subseq;
}
else if (argc == 2) {
beg = NUM2LONG(indx);
len = NUM2LONG(argv[1]);
goto num_index;
}
else if (FIXNUM_P(indx)) {
beg = FIX2LONG(indx);
if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
if (!len) return Qnil;
beg = p - RSTRING_PTR(str);
goto subseq;
}
else if (RB_TYPE_P(indx, T_STRING)) {
beg = rb_str_index(str, indx, 0);
if (beg == -1) return Qnil;
len = RSTRING_LEN(indx);
result = str_duplicate(rb_cString, indx);
goto squash;
}
else {
switch (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 0)) {
case Qnil:
return Qnil;
case Qfalse:
beg = NUM2LONG(indx);
if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
if (!len) return Qnil;
beg = p - RSTRING_PTR(str);
goto subseq;
default:
goto num_index;
}
}
num_index:
if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
beg = p - RSTRING_PTR(str);
subseq:
result = rb_str_new(RSTRING_PTR(str)+beg, len);
rb_enc_cr_str_copy_for_substr(result, str);
squash:
if (len > 0) {
if (beg == 0) {
rb_str_drop_bytes(str, len);
}
else {
char *sptr = RSTRING_PTR(str);
long slen = RSTRING_LEN(str);
if (beg + len > slen) /* pathological check */
len = slen - beg;
memmove(sptr + beg,
sptr + beg + len,
slen - (beg + len));
slen -= len;
STR_SET_LEN(str, slen);
TERM_FILL(&sptr[slen], TERM_LEN(str));
}
}
return result;
} Удаляет указанную часть из str и возвращает удалённую часть.
string = "this is a string"
string.slice!(2) #=> "i"
string.slice!(3..6) #=> " is "
string.slice!(/s.*t/) #=> "sa st"
string.slice!("r") #=> "r"
string #=> "thing"
static VALUE
rb_str_split_m(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
VALUE spat;
VALUE limit;
split_type_t split_type;
long beg, end, i = 0, empty_count = -1;
int lim = 0;
VALUE result, tmp;
result = rb_block_given_p() ? Qfalse : Qnil;
if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) {
lim = NUM2INT(limit);
if (lim <= 0) limit = Qnil;
else if (lim == 1) {
if (RSTRING_LEN(str) == 0)
return result ? rb_ary_new2(0) : str;
tmp = str_duplicate(rb_cString, str);
if (!result) {
rb_yield(tmp);
return str;
}
return rb_ary_new3(1, tmp);
}
i = 1;
}
if (NIL_P(limit) && !lim) empty_count = 0;
enc = STR_ENC_GET(str);
split_type = SPLIT_TYPE_REGEXP;
if (!NIL_P(spat)) {
spat = get_pat_quoted(spat, 0);
}
else if (NIL_P(spat = rb_fs)) {
split_type = SPLIT_TYPE_AWK;
}
else if (!(spat = rb_fs_check(spat))) {
rb_raise(rb_eTypeError, "value of $; must be String or Regexp");
}
else {
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$; is set to non-nil value");
}
if (split_type != SPLIT_TYPE_AWK) {
switch (BUILTIN_TYPE(spat)) {
case T_REGEXP:
rb_reg_options(spat); /* check if uninitialized */
tmp = RREGEXP_SRC(spat);
split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
if (split_type == SPLIT_TYPE_AWK) {
spat = tmp;
split_type = SPLIT_TYPE_STRING;
}
break;
case T_STRING:
mustnot_broken(spat);
split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
break;
default:
UNREACHABLE_RETURN(Qnil);
}
}
#define SPLIT_STR(beg, len) (empty_count = split_string(result, str, beg, len, empty_count))
if (result) result = rb_ary_new();
beg = 0;
char *ptr = RSTRING_PTR(str);
char *eptr = RSTRING_END(str);
if (split_type == SPLIT_TYPE_AWK) {
char *bptr = ptr;
int skip = 1;
unsigned int c;
end = beg;
if (is_ascii_string(str)) {
while (ptr < eptr) {
c = (unsigned char)*ptr++;
if (skip) {
if (ascii_isspace(c)) {
beg = ptr - bptr;
}
else {
end = ptr - bptr;
skip = 0;
if (!NIL_P(limit) && lim <= i) break;
}
}
else if (ascii_isspace(c)) {
SPLIT_STR(beg, end-beg);
skip = 1;
beg = ptr - bptr;
if (!NIL_P(limit)) ++i;
}
else {
end = ptr - bptr;
}
}
}
else {
while (ptr < eptr) {
int n;
c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
ptr += n;
if (skip) {
if (rb_isspace(c)) {
beg = ptr - bptr;
}
else {
end = ptr - bptr;
skip = 0;
if (!NIL_P(limit) && lim <= i) break;
}
}
else if (rb_isspace(c)) {
SPLIT_STR(beg, end-beg);
skip = 1;
beg = ptr - bptr;
if (!NIL_P(limit)) ++i;
}
else {
end = ptr - bptr;
}
}
}
}
else if (split_type == SPLIT_TYPE_STRING) {
char *str_start = ptr;
char *substr_start = ptr;
char *sptr = RSTRING_PTR(spat);
long slen = RSTRING_LEN(spat);
mustnot_broken(str);
enc = rb_enc_check(str, spat);
while (ptr < eptr &&
(end = rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
/* Check we are at the start of a char */
char *t = rb_enc_right_char_head(ptr, ptr + end, eptr, enc);
if (t != ptr + end) {
ptr = t;
continue;
}
SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
ptr += end + slen;
substr_start = ptr;
if (!NIL_P(limit) && lim <= ++i) break;
}
beg = ptr - str_start;
}
else if (split_type == SPLIT_TYPE_CHARS) {
char *str_start = ptr;
int n;
mustnot_broken(str);
enc = rb_enc_get(str);
while (ptr < eptr &&
(n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
SPLIT_STR(ptr - str_start, n);
ptr += n;
if (!NIL_P(limit) && lim <= ++i) break;
}
beg = ptr - str_start;
}
else {
long len = RSTRING_LEN(str);
long start = beg;
long idx;
int last_null = 0;
struct re_registers *regs;
VALUE match = 0;
for (; rb_reg_search(spat, str, start, 0) >= 0;
(match ? (rb_match_unbusy(match), rb_backref_set(match)) : (void)0)) {
match = rb_backref_get();
if (!result) rb_match_busy(match);
regs = RMATCH_REGS(match);
end = BEG(0);
if (start == end && BEG(0) == END(0)) {
if (!ptr) {
SPLIT_STR(0, 0);
break;
}
else if (last_null == 1) {
SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
beg = start;
}
else {
if (start == len)
start++;
else
start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
last_null = 1;
continue;
}
}
else {
SPLIT_STR(beg, end-beg);
beg = start = END(0);
}
last_null = 0;
for (idx=1; idx < regs->num_regs; idx++) {
if (BEG(idx) == -1) continue;
SPLIT_STR(BEG(idx), END(idx)-BEG(idx));
}
if (!NIL_P(limit) && lim <= ++i) break;
}
if (match) rb_match_unbusy(match);
}
if (RSTRING_LEN(str) > 0 && (!NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
SPLIT_STR(beg, RSTRING_LEN(str)-beg);
}
return result ? result : str;
} Разделяет строку str на подстроки на основе разделителя, возвращая массив этих подстрок.
Если pattern является String, его содержимое используется в качестве разделителя при разделении str. Если pattern — это один пробел, str разделяется по пробелам, при этом ведущие и хвостовые пробелы, а также серии последовательных пробелов игнорируются.
Если pattern является Regexp, str делится там, где совпадает шаблон. Всякий раз, когда шаблон совпадает с нулевой строкой, str разделяется на отдельные символы. Если pattern содержит группы, соответствующие совпадения будут возвращены в массиве также.
Если pattern равно nil, используется значение $;. Если $; равно nil (что является значением по умолчанию), str разделяется по пробелам, как если бы был указан ' '.
Если параметр limit опущен, хвостовые нулевые поля подавляются. Если limit — положительное число, будет возвращено не более этого числа разделительных подстрок (захваченные группы также будут возвращены, но не учитываются при подсчете лимита). Если limit равно 1, вся строка возвращается как единственный элемент в массиве. Если отрицательное, нет ограничения на количество возвращаемых полей, и хвостовые нулевые поля не подавляются.
Когда вход str пустой, возвращается пустой Array, так как строка считается не имеющей полей для разделения.
" now's the time ".split #=> ["now's", "the", "time"]
" now's the time ".split(' ') #=> ["now's", "the", "time"]
" now's the time".split(/ /) #=> ["", "now's", "", "the", "time"]
"1, 2.34,56, 7".split(%r{,\s*}) #=> ["1", "2.34", "56", "7"]
"hello".split(//) #=> ["h", "e", "l", "l", "o"]
"hello".split(//, 3) #=> ["h", "e", "llo"]
"hi mom".split(%r{\s*}) #=> ["h", "i", "m", "o", "m"]
"mellow yellow".split("ello") #=> ["m", "w y", "w"]
"1,2,,3,4,,".split(',') #=> ["1", "2", "", "3", "4"]
"1,2,,3,4,,".split(',', 4) #=> ["1", "2", "", "3,4,,"]
"1,2,,3,4,,".split(',', -4) #=> ["1", "2", "", "3", "4", "", ""]
"1:2:3".split(/(:)()()/, 2) #=> ["1", ":", "", "", "2:3"]
"".split(',', -1) #=> []
Если задан блок, вызывается блок с каждой разделенной подстрокой.
static VALUE
rb_str_squeeze(int argc, VALUE *argv, VALUE str)
{
str = str_duplicate(rb_cString, str);
rb_str_squeeze_bang(argc, argv, str);
return str;
} Строит множество символов из параметра(ов) other_str, используя процедуру, описанную для String#count. Возвращает новую строку, где последовательности одинаковых символов, которые входят в это множество, заменяются одним символом. Если аргументы не заданы, все последовательности одинаковых символов заменяются одним символом.
"yellow moon".squeeze #=> "yelow mon"
" now is the".squeeze(" ") #=> " now is the"
"putters shoot balls".squeeze("m-z") #=> "puters shot balls"
static VALUE
rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str)
{
char squeez[TR_TABLE_SIZE];
rb_encoding *enc = 0;
VALUE del = 0, nodel = 0;
unsigned char *s, *send, *t;
int i, modify = 0;
int ascompat, singlebyte = single_byte_optimizable(str);
unsigned int save;
if (argc == 0) {
enc = STR_ENC_GET(str);
}
else {
for (i=0; i<argc; i++) {
VALUE s = argv[i];
StringValue(s);
enc = rb_enc_check(str, s);
if (singlebyte && !single_byte_optimizable(s))
singlebyte = 0;
tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
}
}
str_modify_keep_cr(str);
s = t = (unsigned char *)RSTRING_PTR(str);
if (!s || RSTRING_LEN(str) == 0) return Qnil;
send = (unsigned char *)RSTRING_END(str);
save = -1;
ascompat = rb_enc_asciicompat(enc);
if (singlebyte) {
while (s < send) {
unsigned int c = *s++;
if (c != save || (argc > 0 && !squeez[c])) {
*t++ = save = c;
}
}
}
else {
while (s < send) {
unsigned int c;
int clen;
if (ascompat && (c = *s) < 0x80) {
if (c != save || (argc > 0 && !squeez[c])) {
*t++ = save = c;
}
s++;
}
else {
c = rb_enc_codepoint_len((char *)s, (char *)send, &clen, enc);
if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
if (t != s) rb_enc_mbcput(c, t, enc);
save = c;
t += clen;
}
s += clen;
}
}
}
TERM_FILL((char *)t, TERM_LEN(str));
if ((char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
STR_SET_LEN(str, (char *)t - RSTRING_PTR(str));
modify = 1;
}
if (modify) return str;
return Qnil;
} Сжимает str на месте, возвращая либо str, либо nil если никаких изменений не было.
static VALUE
rb_str_start_with(int argc, VALUE *argv, VALUE str)
{
int i;
for (i=0; i<argc; i++) {
VALUE tmp = argv[i];
if (RB_TYPE_P(tmp, T_REGEXP)) {
if (rb_reg_start_with_p(tmp, str))
return Qtrue;
}
else {
StringValue(tmp);
rb_enc_check(str, tmp);
if (RSTRING_LEN(str) < RSTRING_LEN(tmp)) continue;
if (memcmp(RSTRING_PTR(str), RSTRING_PTR(tmp), RSTRING_LEN(tmp)) == 0)
return Qtrue;
}
}
return Qfalse;
} Возвращает true, если str начинается с одного из prefixes заданных. Каждый из prefixes должен быть String или Regexp.
"hello".start_with?("hell") #=> true
"hello".start_with?(/H/i) #=> true
# returns true if one of the prefixes matches.
"hello".start_with?("heaven", "hell") #=> true
"hello".start_with?("heaven", "paradise") #=> false
static VALUE
rb_str_strip(VALUE str)
{
char *start;
long olen, loffset, roffset;
rb_encoding *enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
loffset = lstrip_offset(str, start, start+olen, enc);
roffset = rstrip_offset(str, start+loffset, start+olen, enc);
if (loffset <= 0 && roffset <= 0) return str_duplicate(rb_cString, str);
return rb_str_subseq(str, loffset, olen-loffset-roffset);
} Возвращает копию объекта-получателя со удаленными начальными и конечными пробелами.
Пробелы определяются как любой из следующих символов: null, табуляция, перевод строки, вертикальная табуляция, символ перевода страницы, возврат каретки, пробел.
" hello ".strip #=> "hello" "\tgoodbye\r\n".strip #=> "goodbye" "\x00\t\n\v\f\r ".strip #=> "" "hello".strip #=> "hello"
static VALUE
rb_str_strip_bang(VALUE str)
{
char *start;
long olen, loffset, roffset;
rb_encoding *enc;
str_modify_keep_cr(str);
enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
loffset = lstrip_offset(str, start, start+olen, enc);
roffset = rstrip_offset(str, start+loffset, start+olen, enc);
if (loffset > 0 || roffset > 0) {
long len = olen-roffset;
if (loffset > 0) {
len -= loffset;
memmove(start, start + loffset, len);
}
STR_SET_LEN(str, len);
#if !SHARABLE_MIDDLE_SUBSTRING
TERM_FILL(start+len, rb_enc_mbminlen(enc));
#endif
return str;
}
return Qnil;
} Удаляет начальные и конечные пробелы из объекта-получателя. Возвращает изменённый объект-получатель, или nil если изменений не было.
Обратитесь к String#strip для определения пробелов.
" hello ".strip! #=> "hello" "hello".strip! #=> nil
static VALUE
rb_str_sub(int argc, VALUE *argv, VALUE str)
{
str = str_duplicate(rb_cString, str);
rb_str_sub_bang(argc, argv, str);
return str;
} Возвращает копию str с заменой первого вхождения pattern вторым аргументом. Второй аргумент обычно является Regexp; если он задан как String, все метасимволы регулярных выражений в нём будут интерпретироваться буквально, например \d будет соответствовать обратной косой черте, за которой следует 'd', а не цифре.
Если второй аргумент — String, он подставляется вместо совпавшей строки. Он может содержать обратные ссылки на группы захвата шаблона в виде \d, где d — номер группы, или \k<n>, где n — имя группы. Аналогично, \&, \', \`, и + соответствуют специальным переменным, $&, $', $`, и $+, соответственно. (См. regexp.rdoc для подробностей.) \0 такое же, как \&. \\ интерпретируется как escape, т.е. как одиночная обратная косая черта. Обратите внимание, что внутри replacement специальные переменные совпадений, такие как $&, не будут ссылаться на текущее совпадение.
Если второй аргумент — Hash, а совпавшая строка является одним из его ключей, соответствующее значение является строкой замены.
В блочной форме текущая строка совпадения передается в качестве параметра, и переменные, такие как $1, $2, $`, $&, и $' будут установлены соответствующим образом. (См. regexp.rdoc для подробностей.) Значение, возвращаемое блоком, будет подставлено для совпадения на каждом вызове.
"hello".sub(/[aeiou]/, '*') #=> "h*llo"
"hello".sub(/([aeiou])/, '<\1>') #=> "h<e>llo"
"hello".sub(/./) {|s| s.ord.to_s + ' ' } #=> "104 ello"
"hello".sub(/(?<foo>[aeiou])/, '*\k<foo>*') #=> "h*e*llo"
'Is SHELL your preferred shell?'.sub(/[[:upper:]]{2,}/, ENV)
#=> "Is /bin/bash your preferred shell?"
Обратите внимание, что строковая литерал потребляет обратные косые черты. (См. syntax/literals.rdoc для получения подробностей о строковых литералах.) Обратные ссылки обычно предваряются дополнительной обратной косой чертой. Например, если вы хотите написать обратную ссылку \& в replacement со строковой литералом с двойными кавычками, вам нужно написать: "..\\&..". Если вы хотите написать строку без обратной ссылки \& в replacement, вам сначала нужно экранировать обратную косую черту, чтобы предотвратить интерпретацию метода её как обратной ссылки, а затем вам нужно экранировать обратные косые черты ещё раз, чтобы предотвратить потребление строковой литералом: "..\\\\&..". Вы можете использовать блочную форму, чтобы избежать большого количества обратных косых черт.
static VALUE
rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
{
VALUE pat, repl, hash = Qnil;
int iter = 0;
long plen;
int min_arity = rb_block_given_p() ? 1 : 2;
long beg;
rb_check_arity(argc, min_arity, 2);
if (argc == 1) {
iter = 1;
}
else {
repl = argv[1];
hash = rb_check_hash_type(argv[1]);
if (NIL_P(hash)) {
StringValue(repl);
}
}
pat = get_pat_quoted(argv[0], 1);
str_modifiable(str);
beg = rb_pat_search(pat, str, 0, 1);
if (beg >= 0) {
rb_encoding *enc;
int cr = ENC_CODERANGE(str);
long beg0, end0;
VALUE match, match0 = Qnil;
struct re_registers *regs;
char *p, *rp;
long len, rlen;
match = rb_backref_get();
regs = RMATCH_REGS(match);
if (RB_TYPE_P(pat, T_STRING)) {
beg0 = beg;
end0 = beg0 + RSTRING_LEN(pat);
match0 = pat;
}
else {
beg0 = BEG(0);
end0 = END(0);
if (iter) match0 = rb_reg_nth_match(0, match);
}
if (iter || !NIL_P(hash)) {
p = RSTRING_PTR(str); len = RSTRING_LEN(str);
if (iter) {
repl = rb_obj_as_string(rb_yield(match0));
}
else {
repl = rb_hash_aref(hash, rb_str_subseq(str, beg0, end0 - beg0));
repl = rb_obj_as_string(repl);
}
str_mod_check(str, p, len);
rb_check_frozen(str);
}
else {
repl = rb_reg_regsub(repl, str, regs, RB_TYPE_P(pat, T_STRING) ? Qnil : pat);
}
enc = rb_enc_compatible(str, repl);
if (!enc) {
rb_encoding *str_enc = STR_ENC_GET(str);
p = RSTRING_PTR(str); len = RSTRING_LEN(str);
if (coderange_scan(p, beg0, str_enc) != ENC_CODERANGE_7BIT ||
coderange_scan(p+end0, len-end0, str_enc) != ENC_CODERANGE_7BIT) {
rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
rb_enc_name(str_enc),
rb_enc_name(STR_ENC_GET(repl)));
}
enc = STR_ENC_GET(repl);
}
rb_str_modify(str);
rb_enc_associate(str, enc);
if (ENC_CODERANGE_UNKNOWN < cr && cr < ENC_CODERANGE_BROKEN) {
int cr2 = ENC_CODERANGE(repl);
if (cr2 == ENC_CODERANGE_BROKEN ||
(cr == ENC_CODERANGE_VALID && cr2 == ENC_CODERANGE_7BIT))
cr = ENC_CODERANGE_UNKNOWN;
else
cr = cr2;
}
plen = end0 - beg0;
rlen = RSTRING_LEN(repl);
len = RSTRING_LEN(str);
if (rlen > plen) {
RESIZE_CAPA(str, len + rlen - plen);
}
p = RSTRING_PTR(str);
if (rlen != plen) {
memmove(p + beg0 + rlen, p + beg0 + plen, len - beg0 - plen);
}
rp = RSTRING_PTR(repl);
memmove(p + beg0, rp, rlen);
len += rlen - plen;
STR_SET_LEN(str, len);
TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
ENC_CODERANGE_SET(str, cr);
return str;
}
return Qnil;
} Выполняет ту же подстановку, что и String#sub, на месте.
Возвращает str если подстановка была выполнена или nil если подстановка не была выполнена.
VALUE
rb_str_succ(VALUE orig)
{
VALUE str;
str = rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
rb_enc_cr_str_copy_for_substr(str, orig);
return str_succ(str);
} Возвращает преемника self. Преемник вычисляется путем инкрементирования символов.
Первый символ, который будет инкрементирован, — это самый правый буквенно-цифровой: или, если нет буквенно-цифровых символов, самый правый символ:
'THX1138'.succ # => "THX1139" '<<koala>>'.succ # => "<<koalb>>" '***'.succ # => '**+'
Преемник цифры — это другая цифра, «переносящая» в следующий слева символ для «переполнения» от 9 до 0 и вставляющая новую цифру, если необходимо:
'00'.succ # => "01" '09'.succ # => "10" '99'.succ # => "100"
Преемник буквы — это другая буква той же буквы, переносимая в следующий слева символ для переполнения, и вставляющая новую букву той же буквы, если необходимо:
'aa'.succ # => "ab" 'az'.succ # => "ba" 'zz'.succ # => "aaa" 'AA'.succ # => "AB" 'AZ'.succ # => "BA" 'ZZ'.succ # => "AAA"
Преемник небуквенно-цифрового символа — это следующий символ в порядке сортировки базового набора символов, переносящийся в следующий слева символ для переполнения и вставляющий новый символ, если необходимо:
s = 0.chr * 3 s # => "\x00\x00\x00" s.succ # => "\x00\x00\x01" s = 255.chr * 3 s # => "\xFF\xFF\xFF" s.succ # => "\x01\x00\x00\x00"
Перенос может происходить между и среди смесей буквенно-цифровых символов:
s = 'zz99zz99' s.succ # => "aaa00aa00" s = '99zz99zz' s.succ # => "100aa00aa"
Преемник пустой строки — это новая пустая строка:
''.succ # => ""
String#next является псевдонимом для String#succ.
static VALUE
rb_str_succ_bang(VALUE str)
{
rb_str_modify(str);
str_succ(str);
return str;
} Эквивалентно String#succ, но изменяет self на месте; возвращает self.
String#next! является псевдонимом для String#succ!.
static VALUE
rb_str_sum(int argc, VALUE *argv, VALUE str)
{
int bits = 16;
char *ptr, *p, *pend;
long len;
VALUE sum = INT2FIX(0);
unsigned long sum0 = 0;
if (rb_check_arity(argc, 0, 1) && (bits = NUM2INT(argv[0])) < 0) {
bits = 0;
}
ptr = p = RSTRING_PTR(str);
len = RSTRING_LEN(str);
pend = p + len;
while (p < pend) {
if (FIXNUM_MAX - UCHAR_MAX < sum0) {
sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
str_mod_check(str, ptr, len);
sum0 = 0;
}
sum0 += (unsigned char)*p;
p++;
}
if (bits == 0) {
if (sum0) {
sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
}
}
else {
if (sum == INT2FIX(0)) {
if (bits < (int)sizeof(long)*CHAR_BIT) {
sum0 &= (((unsigned long)1)<<bits)-1;
}
sum = LONG2FIX(sum0);
}
else {
VALUE mod;
if (sum0) {
sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
}
mod = rb_funcall(INT2FIX(1), idLTLT, 1, INT2FIX(bits));
mod = rb_funcall(mod, '-', 1, INT2FIX(1));
sum = rb_funcall(sum, '&', 1, mod);
}
}
return sum;
} Возвращает батовую контрольную сумму из n битов символов в str, где n — необязательный параметр Integer, по умолчанию равный 16. Результат — просто сумма двоичных значений каждого байта в str по модулю 2**n - 1. Это не очень хорошая контрольная сумма.
static VALUE
rb_str_swapcase(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
VALUE ret;
flags = check_case_options(argc, argv, flags);
enc = str_true_enc(str);
if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str_duplicate(rb_cString, str);
if (flags&ONIGENC_CASE_ASCII_ONLY) {
ret = rb_str_new(0, RSTRING_LEN(str));
rb_str_ascii_casemap(str, ret, &flags, enc);
}
else {
ret = rb_str_casemap(str, &flags, enc);
}
return ret;
} Возвращает копию str, в которой заглавные буквы латинского алфавита заменены на строчные, а строчные — на заглавные.
См. String#downcase для значения options и использования с различными кодировками.
"Hello".swapcase #=> "hELLO" "cYbEr_PuNk11".swapcase #=> "CyBeR_pUnK11"
static VALUE
rb_str_swapcase_bang(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
flags = check_case_options(argc, argv, flags);
str_modify_keep_cr(str);
enc = str_true_enc(str);
if (flags&ONIGENC_CASE_ASCII_ONLY)
rb_str_ascii_casemap(str, str, &flags, enc);
else
str_shared_replace(str, rb_str_casemap(str, &flags, enc));
if (ONIGENC_CASE_MODIFIED&flags) return str;
return Qnil;
} Эквивалентно String#swapcase, но изменяет получатель на месте, возвращая str или nil , если изменений не произошло.
См. String#downcase для значения options и использования с различными кодировками.
static VALUE
string_to_c(VALUE self)
{
char *s;
VALUE num;
rb_must_asciicompat(self);
s = RSTRING_PTR(self);
if (s && s[RSTRING_LEN(self)]) {
rb_str_modify(self);
s = RSTRING_PTR(self);
s[RSTRING_LEN(self)] = '\0';
}
if (!s)
s = (char *)"";
(void)parse_comp(s, 0, &num);
return num;
} Возвращает комплексное число, соответствующее строковой форме. Парсер игнорирует начальные пробелы и конечный мусор. Любые последовательности цифр могут быть разделены символом нижнего подчеркивания. Возвращает ноль для пустой или мусорной строки.
'9'.to_c #=> (9+0i) '2.5'.to_c #=> (2.5+0i) '2.5/1'.to_c #=> ((5/2)+0i) '-3/2'.to_c #=> ((-3/2)+0i) '-i'.to_c #=> (0-1i) '45i'.to_c #=> (0+45i) '3-4i'.to_c #=> (3-4i) '-4e2-4e-2i'.to_c #=> (-400.0-0.04i) '-0.0-0.0i'.to_c #=> (-0.0-0.0i) '1/2+3/4i'.to_c #=> ((1/2)+(3/4)*i) 'ruby'.to_c #=> (0+0i)
См. Kernel.Complex.
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 68 def to_d BigDecimal.interpret_loosely(self) end
Возвращает результат интерпретации начальных символов в str как BigDecimal.
require 'bigdecimal' require 'bigdecimal/util' "0.5".to_d # => 0.5e0 "123.45e1".to_d # => 0.12345e4 "45.67 degrees".to_d # => 0.4567e2
См. также BigDecimal::new.
static VALUE
rb_str_to_f(VALUE str)
{
return DBL2NUM(rb_str_to_dbl(str, FALSE));
} Возвращает результат интерпретации начальных символов в str как число с плавающей точкой. Дополнительные символы после окончания допустимого числа игнорируются. Если в начале str нет допустимого числа, возвращается 0.0. Этот метод никогда не вызывает исключение.
"123.45e1".to_f #=> 1234.5 "45.67 degrees".to_f #=> 45.67 "thx1138".to_f #=> 0.0
static VALUE
rb_str_to_i(int argc, VALUE *argv, VALUE str)
{
int base = 10;
if (rb_check_arity(argc, 0, 1) && (base = NUM2INT(argv[0])) < 0) {
rb_raise(rb_eArgError, "invalid radix %d", base);
}
return rb_str_to_inum(str, base, FALSE);
} Возвращает результат интерпретации начальных символов в str как целое число по основанию base (от 2 до 36). Дополнительные символы после окончания допустимого числа игнорируются. Если в начале str нет допустимого числа, возвращается 0. Этот метод никогда не вызывает исключение, когда base допустимо.
"12345".to_i #=> 12345 "99 red balloons".to_i #=> 99 "0a".to_i #=> 0 "0a".to_i(16) #=> 10 "hello".to_i #=> 0 "1100101".to_i(2) #=> 101 "1100101".to_i(8) #=> 294977 "1100101".to_i(10) #=> 1100101 "1100101".to_i(16) #=> 17826049
static VALUE
string_to_r(VALUE self)
{
VALUE num;
rb_must_asciicompat(self);
num = parse_rat(RSTRING_PTR(self), RSTRING_END(self), 0, TRUE);
if (RB_FLOAT_TYPE_P(num) && !FLOAT_ZERO_P(num))
rb_raise(rb_eFloatDomainError, "Infinity");
return num;
} Возвращает результат интерпретации начальных символов в str как рациональное число. Начальные пробелы и дополнительные символы после окончания допустимого числа игнорируются. Последовательности цифр могут быть разделены символом нижнего подчеркивания. Если в начале str нет допустимого числа, возвращается ноль. Этот метод никогда не вызывает исключение.
' 2 '.to_r #=> (2/1) '300/2'.to_r #=> (150/1) '-9.2'.to_r #=> (-46/5) '-9.2e2'.to_r #=> (-920/1) '1_234_567'.to_r #=> (1234567/1) '21 June 09'.to_r #=> (21/1) '21/06/09'.to_r #=> (7/2) 'BWV 1079'.to_r #=> (0/1)
ПРИМЕЧАНИЕ: “0.3”.to_r не равно 0.3.to_r. Первый эквивалентен “3/10”.to_r, но второй нет.
"0.3".to_r == 3/10r #=> true 0.3.to_r == 3/10r #=> false
См. также Kernel#Rational.
static VALUE
rb_str_to_s(VALUE str)
{
if (rb_obj_class(str) != rb_cString) {
return str_duplicate(rb_cString, str);
}
return str;
} Возвращает self.
Если вызывается на подклассе String, преобразует получатель в объект String.
Возвращает Symbol, соответствующую str, создавая символ, если он ранее не существовал. См. Symbol#id2name.
"Koala".intern #=> :Koala s = 'cat'.to_sym #=> :cat s == :cat #=> true s = '@cat'.to_sym #=> :@cat s == :@cat #=> true
Это также можно использовать для создания символов, которые нельзя представить с помощью :xxx нотации.
'cat and dog'.to_sym #=> :"cat and dog"
# File ext/nkf/lib/kconv.rb, line 224 def toeuc; Kconv.toeuc(self) end
Преобразовать self в EUC-JP
# File ext/nkf/lib/kconv.rb, line 218 def tojis; Kconv.tojis(self) end
Преобразовать self в ISO-2022-JP
# File ext/nkf/lib/kconv.rb, line 254 def tolocale; Kconv.tolocale(self) end
Преобразовать self в кодировку локали
# File ext/nkf/lib/kconv.rb, line 230 def tosjis; Kconv.tosjis(self) end
Преобразовать self в Shift_JIS
# File ext/nkf/lib/kconv.rb, line 242 def toutf16; Kconv.toutf16(self) end
Преобразовать self в UTF-16
# File ext/nkf/lib/kconv.rb, line 248 def toutf32; Kconv.toutf32(self) end
Преобразовать self в UTF-32
# File ext/nkf/lib/kconv.rb, line 236 def toutf8; Kconv.toutf8(self) end
Преобразовать self в UTF-8
static VALUE
rb_str_tr(VALUE str, VALUE src, VALUE repl)
{
str = str_duplicate(rb_cString, str);
tr_trans(str, src, repl, 0);
return str;
} Возвращает копию str с символами из from_str , заменёнными соответствующими символами в to_str. Если to_str короче from_str, он дополняется своим последним символом, чтобы сохранить соответствие.
"hello".tr('el', 'ip') #=> "hippo"
"hello".tr('aeiou', '*') #=> "h*ll*"
"hello".tr('aeiou', 'AA*') #=> "hAll*"
Обе строки могут использовать c1-c2 нотацию для обозначения диапазонов символов, и from_str может начинаться с ^, что обозначает все символы, кроме перечисленных.
"hello".tr('a-y', 'b-z') #=> "ifmmp"
"hello".tr('^aeiou', '*') #=> "*e**o"
Символ обратного слэша \ может использоваться для экранирования ^ или - и в противном случае игнорируется, если он не появляется в конце диапазона или в конце from_str или to_str.
"hello^world".tr("\\^aeiou", "*") #=> "h*ll**w*rld"
"hello-world".tr("a\\-eo", "*") #=> "h*ll**w*rld"
"hello\r\nworld".tr("\r", "") #=> "hello\nworld"
"hello\r\nworld".tr("\\r", "") #=> "hello\r\nwold"
"hello\r\nworld".tr("\\\r", "") #=> "hello\nworld"
"X['\\b']".tr("X\\", "") #=> "['b']"
"X['\\b']".tr("X-\\]", "") #=> "'b'"
static VALUE
rb_str_tr_bang(VALUE str, VALUE src, VALUE repl)
{
return tr_trans(str, src, repl, 0);
} Перевод str на месте, используя те же правила, что и String#tr. Возвращает str или nil , если изменений не произошло.
static VALUE
rb_str_tr_s(VALUE str, VALUE src, VALUE repl)
{
str = str_duplicate(rb_cString, str);
tr_trans(str, src, repl, 1);
return str;
} Обрабатывает копию str, как описано в String#tr, затем удаляет повторяющиеся символы в регионах, которые были затронуты переводом.
"hello".tr_s('l', 'r') #=> "hero"
"hello".tr_s('el', '*') #=> "h*o"
"hello".tr_s('el', 'hx') #=> "hhxo"
static VALUE
rb_str_tr_s_bang(VALUE str, VALUE src, VALUE repl)
{
return tr_trans(str, src, repl, 1);
} Выполняет обработку String#tr_s над str на месте, возвращая str или nil, если изменений не было.
static VALUE
str_undump(VALUE str)
{
const char *s = RSTRING_PTR(str);
const char *s_end = RSTRING_END(str);
rb_encoding *enc = rb_enc_get(str);
VALUE undumped = rb_enc_str_new(s, 0L, enc);
bool utf8 = false;
bool binary = false;
int w;
rb_must_asciicompat(str);
if (rb_str_is_ascii_only_p(str) == Qfalse) {
rb_raise(rb_eRuntimeError, "non-ASCII character detected");
}
if (!str_null_check(str, &w)) {
rb_raise(rb_eRuntimeError, "string contains null byte");
}
if (RSTRING_LEN(str) < 2) goto invalid_format;
if (*s != '"') goto invalid_format;
/* strip '"' at the start */
s++;
for (;;) {
if (s >= s_end) {
rb_raise(rb_eRuntimeError, "unterminated dumped string");
}
if (*s == '"') {
/* epilogue */
s++;
if (s == s_end) {
/* ascii compatible dumped string */
break;
}
else {
static const char force_encoding_suffix[] = ".force_encoding(\""; /* "\")" */
static const char dup_suffix[] = ".dup";
const char *encname;
int encidx;
ptrdiff_t size;
/* check separately for strings dumped by older versions */
size = sizeof(dup_suffix) - 1;
if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;
size = sizeof(force_encoding_suffix) - 1;
if (s_end - s <= size) goto invalid_format;
if (memcmp(s, force_encoding_suffix, size) != 0) goto invalid_format;
s += size;
if (utf8) {
rb_raise(rb_eRuntimeError, "dumped string contained Unicode escape but used force_encoding");
}
encname = s;
s = memchr(s, '"', s_end-s);
size = s - encname;
if (!s) goto invalid_format;
if (s_end - s != 2) goto invalid_format;
if (s[0] != '"' || s[1] != ')') goto invalid_format;
encidx = rb_enc_find_index2(encname, (long)size);
if (encidx < 0) {
rb_raise(rb_eRuntimeError, "dumped string has unknown encoding name");
}
rb_enc_associate_index(undumped, encidx);
}
break;
}
if (*s == '\\') {
s++;
if (s >= s_end) {
rb_raise(rb_eRuntimeError, "invalid escape");
}
undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
}
else {
rb_str_cat(undumped, s++, 1);
}
}
return undumped;
invalid_format:
rb_raise(rb_eRuntimeError, "invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
} Возвращает неэкранированную версию строки. Это обратная операция к String#dump.
"\"hello \\n ''\"".undump #=> "hello \n ''"
static VALUE
rb_str_unicode_normalize(int argc, VALUE *argv, VALUE str)
{
return unicode_normalize_common(argc, argv, str, id_normalize);
} Нормализация Unicode — возвращает нормализованную форму str, используя Unicode-нормализации NFC, NFD, NFKC или NFKD. Используемая форма нормализации определяется form, которое может принимать любое из четырёх значений :nfc, :nfd, :nfkc, или :nfkd. По умолчанию используется :nfc.
Если строка не в формате Unicode Encoding, то генерируется исключение Exception. В данном контексте 'кодировка Unicode' подразумевает UTF-8, UTF-16BE/LE, UTF-32BE/LE, а также GB18030, UCS_2BE и UCS_4BE. Любой формат кроме UTF-8 реализуется путём преобразования в UTF-8, что делает его медленнее, чем UTF-8.
"a\u0300".unicode_normalize #=> "\u00E0"
"a\u0300".unicode_normalize(:nfc) #=> "\u00E0"
"\u00E0".unicode_normalize(:nfd) #=> "a\u0300"
"\xE0".force_encoding('ISO-8859-1').unicode_normalize(:nfd)
#=> Encoding::CompatibilityError raised
static VALUE
rb_str_unicode_normalize_bang(int argc, VALUE *argv, VALUE str)
{
return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
} Деструктивная версия String#unicode_normalize, выполняющая нормализацию Unicode на месте.
static VALUE
rb_str_unicode_normalized_p(int argc, VALUE *argv, VALUE str)
{
return unicode_normalize_common(argc, argv, str, id_normalized_p);
} Проверяет, находится ли str в форме Unicode-нормализации form, которая может принимать любое из четырёх значений :nfc, :nfd, :nfkc, или :nfkd. По умолчанию используется :nfc.
Если строка не в формате Unicode Encoding, то генерируется исключение Exception. Подробнее см. String#unicode_normalize.
"a\u0300".unicode_normalized? #=> false
"a\u0300".unicode_normalized?(:nfd) #=> true
"\u00E0".unicode_normalized? #=> true
"\u00E0".unicode_normalized?(:nfd) #=> false
"\xE0".force_encoding('ISO-8859-1').unicode_normalized?
#=> Encoding::CompatibilityError raised
# File pack.rb, line 256 def unpack(fmt) Primitive.pack_unpack(fmt) end
Декодирует str (которое может содержать двоичные данные) в соответствии с строкой формата, возвращая массив из каждого извлечённого значения. Строка формата состоит из последовательности символьных директив, суммированных в таблице в конце этой записи. Каждая директива может быть после-довательностями с числом, указывающим количество повторов этой директивы. Звёздочка («*'') использует все оставшиеся элементы. Директивы sSiIlL могут быть после-довательностями с подчёркиванием («_'') или восклицательным знаком («!'') для использования родного размера платформы для указанного типа; в противном случае используется независимый от платформы размер. Пробелы в строке формата игнорируются. См. также String#unpack1, Array#pack.
"abc \0\0abc \0\0".unpack('A6Z6') #=> ["abc", "abc "]
"abc \0\0".unpack('a3a3') #=> ["abc", " \000\000"]
"abc \0abc \0".unpack('Z*Z*') #=> ["abc ", "abc "]
"aa".unpack('b8B8') #=> ["10000110", "01100001"]
"aaa".unpack('h2H2c') #=> ["16", "61", 97]
"\xfe\xff\xfe\xff".unpack('sS') #=> [-2, 65534]
"now=20is".unpack('M*') #=> ["now is"]
"whole".unpack('xax2aX2aX1aX2a') #=> ["h", "e", "l", "l", "o"]
В этой таблице суммируются различные форматы и Ruby классы, возвращаемые каждым из них.
Integer | |
Directive | Returns | Meaning
------------------------------------------------------------------
C | Integer | 8-bit unsigned (unsigned char)
S | Integer | 16-bit unsigned, native endian (uint16_t)
L | Integer | 32-bit unsigned, native endian (uint32_t)
Q | Integer | 64-bit unsigned, native endian (uint64_t)
J | Integer | pointer width unsigned, native endian (uintptr_t)
| |
c | Integer | 8-bit signed (signed char)
s | Integer | 16-bit signed, native endian (int16_t)
l | Integer | 32-bit signed, native endian (int32_t)
q | Integer | 64-bit signed, native endian (int64_t)
j | Integer | pointer width signed, native endian (intptr_t)
| |
S_ S! | Integer | unsigned short, native endian
I I_ I! | Integer | unsigned int, native endian
L_ L! | Integer | unsigned long, native endian
Q_ Q! | Integer | unsigned long long, native endian (ArgumentError
| | if the platform has no long long type.)
J! | Integer | uintptr_t, native endian (same with J)
| |
s_ s! | Integer | signed short, native endian
i i_ i! | Integer | signed int, native endian
l_ l! | Integer | signed long, native endian
q_ q! | Integer | signed long long, native endian (ArgumentError
| | if the platform has no long long type.)
j! | Integer | intptr_t, native endian (same with j)
| |
S> s> S!> s!> | Integer | same as the directives without ">" except
L> l> L!> l!> | | big endian
I!> i!> | |
Q> q> Q!> q!> | | "S>" is same as "n"
J> j> J!> j!> | | "L>" is same as "N"
| |
S< s< S!< s!< | Integer | same as the directives without "<" except
L< l< L!< l!< | | little endian
I!< i!< | |
Q< q< Q!< q!< | | "S<" is same as "v"
J< j< J!< j!< | | "L<" is same as "V"
| |
n | Integer | 16-bit unsigned, network (big-endian) byte order
N | Integer | 32-bit unsigned, network (big-endian) byte order
v | Integer | 16-bit unsigned, VAX (little-endian) byte order
V | Integer | 32-bit unsigned, VAX (little-endian) byte order
| |
U | Integer | UTF-8 character
w | Integer | BER-compressed integer (see Array#pack)
Float | |
Directive | Returns | Meaning
-----------------------------------------------------------------
D d | Float | double-precision, native format
F f | Float | single-precision, native format
E | Float | double-precision, little-endian byte order
e | Float | single-precision, little-endian byte order
G | Float | double-precision, network (big-endian) byte order
g | Float | single-precision, network (big-endian) byte order
String | |
Directive | Returns | Meaning
-----------------------------------------------------------------
A | String | arbitrary binary string (remove trailing nulls and ASCII spaces)
a | String | arbitrary binary string
Z | String | null-terminated string
B | String | bit string (MSB first)
b | String | bit string (LSB first)
H | String | hex string (high nibble first)
h | String | hex string (low nibble first)
u | String | UU-encoded string
M | String | quoted-printable, MIME encoding (see RFC2045)
m | String | base64 encoded string (RFC 2045) (default)
| | base64 encoded string (RFC 4648) if followed by 0
P | String | pointer to a structure (fixed-length string)
p | String | pointer to a null-terminated string
Misc. | |
Directive | Returns | Meaning
-----------------------------------------------------------------
@ | --- | skip to the offset given by the length argument
X | --- | skip backward one byte
x | --- | skip forward one byte ИСТОРИЯ
-
J, J! j, и j! доступны с Ruby 2.3.
-
Q_, Q!, q_, и q! доступны с Ruby 2.1.
-
I!<, i!<, I!>, и i!> доступны с Ruby 1.9.3.
# File pack.rb, line 280 def unpack1(fmt) Primitive.pack_unpack1(fmt) end
Декодирует str (которое может содержать двоичные данные) в соответствии с строкой формата, возвращая первое извлечённое значение. См. также String#unpack, Array#pack.
Противопоставление String#unpack:
"abc \0\0abc \0\0".unpack('A6Z6') #=> ["abc", "abc "]
"abc \0\0abc \0\0".unpack1('A6Z6') #=> "abc"
В этом случае данные будут утеряны, но часто бывает так, что массив содержит только одно значение, особенно при распаковке двоичных данных. Например:
“xffx00x00x00”.unpack(“l”) #=> [255] “xffx00x00x00”.unpack1(“l”) #=> 255
Таким образом, unpack1 удобно, делает ясным намерение и сигнализирует ожидаемое возвращаемое значение тем, кто читает код.
static VALUE
rb_str_upcase(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
VALUE ret;
flags = check_case_options(argc, argv, flags);
enc = str_true_enc(str);
if (case_option_single_p(flags, enc, str)) {
ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
str_enc_copy(ret, str);
upcase_single(ret);
}
else if (flags&ONIGENC_CASE_ASCII_ONLY) {
ret = rb_str_new(0, RSTRING_LEN(str));
rb_str_ascii_casemap(str, ret, &flags, enc);
}
else {
ret = rb_str_casemap(str, &flags, enc);
}
return ret;
} Возвращает копию str, где все строчные буквы заменены на прописные.
См. String#downcase для значения options и использования с различными кодировками.
"hEllO".upcase #=> "HELLO"
static VALUE
rb_str_upcase_bang(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
flags = check_case_options(argc, argv, flags);
str_modify_keep_cr(str);
enc = str_true_enc(str);
if (case_option_single_p(flags, enc, str)) {
if (upcase_single(str))
flags |= ONIGENC_CASE_MODIFIED;
}
else if (flags&ONIGENC_CASE_ASCII_ONLY)
rb_str_ascii_casemap(str, str, &flags, enc);
else
str_shared_replace(str, rb_str_casemap(str, &flags, enc));
if (ONIGENC_CASE_MODIFIED&flags) return str;
return Qnil;
} Преобразует содержимое str в верхний регистр, возвращая nil если изменений не было.
См. String#downcase для значения options и использования с различными кодировками.
static VALUE
rb_str_upto(int argc, VALUE *argv, VALUE beg)
{
VALUE end, exclusive;
rb_scan_args(argc, argv, "11", &end, &exclusive);
RETURN_ENUMERATOR(beg, argc, argv);
return rb_str_upto_each(beg, end, RTEST(exclusive), str_upto_i, Qnil);
} При использовании блока, вызывает блок для каждой строки, возвращаемой последовательными вызовами String#succ; первое значение — self, следующее — self.succ, и так далее; последовательность завершается, когда достигается значение other_string; возвращает self:
'a8'.upto('b6') {|s| print s, ' ' } # => "a8"
Вывод:
a8 a9 b0 b1 b2 b3 b4 b5 b6
Если аргумент exclusive задан как истинное значение, последнее значение пропускается:
'a8'.upto('b6', true) {|s| print s, ' ' } # => "a8"
Вывод:
a8 a9 b0 b1 b2 b3 b4 b5
Если other_string не будет достигнуто, блок не вызывается:
'25'.upto('5') {|s| fail s }
'aa'.upto('a') {|s| fail s }
Без блока возвращает новый Enumerator:
'a8'.upto('b6') # => #<Enumerator: "a8":upto("b6")>
static VALUE
rb_str_valid_encoding_p(VALUE str)
{
int cr = rb_enc_str_coderange(str);
return cr == ENC_CODERANGE_BROKEN ? Qfalse : Qtrue;
} Возвращает true для строки, которая закодирована правильно.
"\xc2\xa1".force_encoding("UTF-8").valid_encoding? #=> true
"\xc2".force_encoding("UTF-8").valid_encoding? #=> false
"\x80".force_encoding("UTF-8").valid_encoding? #=> false
Ruby Core © 1993–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.