класс String
Объект String содержит произвольную последовательность байтов, обычно представляющую текст или двоичные данные. Объект String можно создать с помощью String::new или в виде литерала.
Объекты String отличаются от объектов Symbol тем, что объекты Symbol предназначены для использования в качестве идентификаторов, а не текста или данных.
Создать объект String явно можно с помощью:
Некоторые объекты можно преобразовать в строки с помощью:
-
Метода
String.
Некоторые методы String изменяют self. Обычно метод, имя которого заканчивается на !, изменяет self и возвращает self; часто одноимённый метод (без !) возвращает новую строку.
Как правило, если у метода есть версии с восклицательным знаком и без него, метод с восклицательным знаком изменяет объект, а метод без него — нет. Однако метод без восклицательного знака тоже может изменять объект, например String#replace.
Методы подстановки
Эти методы выполняют подстановки:
-
String#sub: одна подстановка (или ни одной); возвращает новую строку. -
String#sub!: одна подстановка (или ни одной); возвращаетself, если были изменения, иnilв противном случае. -
String#gsub: ноль или более подстановок; возвращает новую строку. -
String#gsub!: ноль или более подстановок; возвращаетself, если были изменения, иnilв противном случае.
Каждый из этих методов принимает:
-
Первый аргумент,
pattern(StringилиRegexp), который указывает подстроку (или подстроки), подлежащую замене. -
Один из следующих вариантов:
В примерах этого раздела в основном используются методы String#sub и String#gsub; описанные принципы применимы ко всем четырём методам подстановки.
Аргумент pattern
Аргумент pattern обычно является регулярным выражением:
s = 'hello' s.sub(/[aeiou]/, '*') # => "h*llo" s.gsub(/[aeiou]/, '*') # => "h*ll*" s.gsub(/[aeiou]/, '') # => "hll" s.sub(/ell/, 'al') # => "halo" s.gsub(/xyzzy/, '*') # => "hello" 'THX1138'.gsub(/\d+/, '00') # => "THX00"
Если pattern — строка, все её символы трактуются как обычные символы (а не как специальные символы Regexp):
'THX1138'.gsub('\d+', '00') # => "THX1138"
String replacement
Если replacement — строка, она определяет строку замены, которой подменяется совпавший текст.
Во всех приведённых выше примерах в качестве строки замены используется простая строка.
String replacement может содержать обратные ссылки на захваты шаблона:
-
\n(где n — неотрицательное целое число) ссылается на$n. -
\k<name>ссылается на именованный захватname.
Подробности см. в разделе Regexp.
Обратите внимание: в строке replacement комбинация символов, например $&, трактуется как обычный текст, а не как специальная переменная совпадения. Однако на некоторые специальные переменные совпадения можно ссылаться с помощью следующих комбинаций:
-
\&и\0соответствуют$&, содержащей весь совпавший текст. -
\'соответствует$', содержащей строку после совпадения. -
\`соответствует$`, содержащей строку перед совпадением. -
\+соответствует$+, содержащей последнюю группу захвата.
Подробности см. в разделе Regexp.
Обратите внимание, что \\ интерпретируется как экранирующий символ, то есть как одна обратная косая черта.
Также обратите внимание, что строковый литерал поглощает обратные косые черты. Подробности о строковых литералах см. в разделе Строковые литералы.
Перед обратной ссылкой обычно ставится дополнительная обратная косая черта. Например, если вы хотите записать обратную ссылку \& в replacement с помощью строкового литерала в двойных кавычках, необходимо написать "..\\&..".
Если вы хотите записать строку, не являющуюся обратной ссылкой, \& в replacement, сначала нужно экранировать обратную косую черту, чтобы этот метод не интерпретировал её как обратную ссылку, а затем ещё раз экранировать обратные косые черты, чтобы строковый литерал их не поглотил: "..\\\\&..".
Чтобы избежать чрезмерного количества обратных косых черт, можно использовать форму с блоком.
Хеш replacement
Если аргумент replacement — хеш и pattern совпадает с одним из его ключей, в качестве строки замены используется значение, соответствующее этому ключу:
h = {'foo' => 'bar', 'baz' => 'bat'}
'food'.sub('foo', h) # => "bard"
Обратите внимание: ключ-символ не даёт совпадения:
h = {foo: 'bar', baz: 'bat'}
'food'.sub('foo', h) # => "d"
Блок
В форме с блоком текущая строка совпадения передаётся блоку; возвращаемое блоком значение становится строкой замены:
s = '@'
'1234'.gsub(/\d/) { |match| s.succ! } # => "ABCD"
Специальные переменные совпадения, такие как $1, $2, $`, $& и $', получают соответствующие значения.
Пробельные символы в строках
В классе String пробельные символы определяются как непрерывная последовательность символов, состоящая из любых комбинаций следующих элементов:
-
NL (нулевой символ):
"\x00","\u0000". -
HT (горизонтальная табуляция):
"\x09","\t". -
LF (перевод строки):
"\x0a","\n". -
VT (вертикальная табуляция):
"\x0b","\v". -
FF (перевод страницы):
"\x0c","\f". -
CR (возврат каретки):
"\x0d","\r". -
SP (пробел):
"\x20"," ".
Пробельные символы используются в следующих методах:
-
lstrip,lstrip!: удаление пробельных символов в начале строки. -
rstrip,rstrip!: удаление пробельных символов в конце строки. -
strip,strip!: удаление пробельных символов в начале и конце строки.
Что здесь находится
Сначала — что находится в других разделах. Класс String:
-
Наследуется от класса Object.
-
Подключает модуль Comparable.
В этом разделе класс String предоставляет методы для:
Создание строки
-
::new: возвращает новую строку. -
::try_convert: возвращает новую строку, созданную из заданного объекта.
Заморозка и разморозка
-
+@: возвращает незамороженную строку:self, если строка не заморожена; в противном случае —self.dup. -
-@(имеет псевдонимdedup): возвращает замороженную строку:self, если строка уже заморожена; в противном случае —self.freeze. -
freeze: замораживаетself, если она ещё не заморожена; возвращаетself.
Получение сведений
Количество
-
bytesize: возвращает количество байтов. -
count: возвращает количество подстрок, совпадающих с заданными строками. -
empty?: возвращает значение, указывающее, равна ли длинаselfнулю. -
length(имеет псевдонимsize): возвращает количество символов (не байтов).
Подстроки
-
=~: возвращает индекс первой подстроки, совпавшей с заданнымRegexpили другим объектом; если совпадение не найдено, возвращаетnil. -
byteindex: возвращает байтовый индекс первого вхождения заданной подстроки. -
byterindex: возвращает байтовый индекс последнего вхождения заданной подстроки. -
index: возвращает индекс первого вхождения заданной подстроки; если совпадений нет, возвращаетnil. -
rindex: возвращает индекс последнего вхождения заданной подстроки; если совпадений нет, возвращаетnil. -
include?: возвращаетtrue, если строка содержит заданную подстроку; в противном случае —false. -
match: возвращает объектMatchData, если строка соответствует заданномуRegexp; в противном случае —nil. -
match?: возвращаетtrue, если строка соответствует заданномуRegexp; в противном случае —false. -
start_with?: возвращаетtrue, если строка начинается с любой из заданных подстрок. -
end_with?: возвращаетtrue, если строка заканчивается любой из заданных подстрок.
Кодировки
-
encoding: возвращает объектEncoding, представляющий кодировку строки. -
unicode_normalized?: возвращаетtrue, если строка находится в нормализованной форме Unicode; в противном случае —false. -
valid_encoding?: возвращаетtrue, если строка содержит только символы, допустимые для её кодировки. -
ascii_only?: возвращаетtrue, если строка содержит только символы ASCII; в противном случае —false.
Прочее
-
sum: возвращает простую контрольную сумму строки — сумму значений всех байтов. -
hash: возвращает целочисленный хеш-код.
Сравнение
-
==(также известен как===): Возвращаетtrue, если заданная другая строка имеет то же содержимое, что иself. -
eql?: Возвращаетtrue, если содержимое совпадает с содержимым заданной другой строки. -
<=>: Возвращает -1, 0 или 1 в зависимости от того, меньше ли заданная другая строка, равна ли или большеself. -
casecmp: Без учета регистра возвращает -1, 0 или 1 в зависимости от того, меньше лиself, равна ли или больше заданной другой строки. -
casecmp?: Без учета регистра возвращает, равна ли заданная другая строкаself.
Изменение
Каждый из этих методов изменяет self.
Вставка
-
insert: Возвращаетselfсо вставленной в указанную позицию заданной строкой. -
<<: Возвращаетself, объединённую с заданной строкой или целым числом. -
append_as_bytes: Возвращаетself, объединённую со строками без проверки или преобразования кодировки. -
prepend: Добавляет в началоselfобъединение заданных других строк.
Замена
-
bytesplice: Заменяет байтыselfбайтами из заданной строки; возвращаетself. -
sub!: Заменяет первую подстроку, соответствующую заданному шаблону, заданной строкой-заменой; возвращаетself, если были внесены изменения, иnilв противном случае. -
gsub!: Заменяет каждую подстроку, соответствующую заданному шаблону, заданной строкой-заменой; возвращаетself, если были внесены изменения, иnilв противном случае. -
succ!(также известен какnext!): Возвращаетself, изменённую так, чтобы она стала своим собственным преемником. -
replace: Возвращаетself, полностью заменив её содержимое заданной строкой. -
reverse!: Возвращаетselfс символами в обратном порядке. -
setbyte: Устанавливает заданное значение для байта по заданному целочисленному смещению; возвращает аргумент. -
tr!: Заменяет указанные символы вselfуказанными символами-заменами; возвращаетself, если были внесены изменения, иnilв противном случае. -
tr_s!: Заменяет указанные символы вselfуказанными символами-заменами, удаляя дубликаты из изменённых подстрок; возвращаетself, если были внесены изменения, иnilв противном случае.
Регистр
-
capitalize!: Переводит первый символ в верхний регистр, а все остальные — в нижний; возвращаетself, если были внесены изменения, иnilв противном случае. -
downcase!: Переводит все символы в нижний регистр; возвращаетself, если были внесены изменения, иnilв противном случае. -
upcase!: Переводит все символы в верхний регистр; возвращаетself, если были внесены изменения, иnilв противном случае. -
swapcase!: Переводит каждый символ в нижнем регистре в верхний, а каждый символ в верхнем регистре — в нижний; возвращаетself, если были внесены изменения, иnilв противном случае.
Кодировка
-
encode!: Возвращаетself, в которой все символы преобразованы из одной кодировки в другую. -
unicode_normalize!: Выполняет нормализацию Unicode дляself; возвращаетself. -
scrub!: Заменяет каждый недопустимый байт заданным символом; возвращаетself. -
force_encoding: Изменяет кодировку на заданную; возвращаетself.
Удаление
-
clear: Удаляет всё содержимое, оставляяselfпустой; возвращаетself. -
slice!,[]=: Удаляет подстроку, определяемую заданным индексом, начальной позицией и длиной, диапазоном, регулярным выражением или подстрокой. -
squeeze!: Удаляет подряд идущие повторяющиеся символы; возвращаетself. -
delete!: Удаляет символы, определяемые пересечением аргументов-подстрок. -
delete_prefix!: Удаляет начальный префикс; возвращаетself, если были внесены изменения, иnilв противном случае. -
delete_suffix!: Удаляет конечный суффикс; возвращаетself, если были внесены изменения, иnilв противном случае. -
lstrip!: Удаляет начальные пробельные символы; возвращаетself, если были внесены изменения, иnilв противном случае. -
rstrip!: Удаляет конечные пробельные символы; возвращаетself, если были внесены изменения, иnilв противном случае. -
strip!: Удаляет начальные и конечные пробельные символы; возвращаетself, если были внесены изменения, иnilв противном случае. -
chomp!: Удаляет конечный разделитель записей, если он найден; возвращаетself, если были внесены изменения, иnilв противном случае. -
chop!: Удаляет конечные символы новой строки, если они найдены; в противном случае удаляет последний символ; возвращаетself, если были внесены изменения, иnilв противном случае.
Преобразование в новую строку
Каждый из этих методов возвращает новую String на основе self, часто просто изменённую копию self.
Расширение
-
*: Возвращает объединение нескольких копийself. -
+: Возвращает объединениеselfи заданной другой строки. -
center: Возвращает копиюself, выровненную по центру с указанными символами-заполнителями. -
concat: Возвращает объединениеselfс заданными другими строками. -
ljust: Возвращает копиюselfзаданной длины, дополненную справа заданной другой строкой. -
rjust: Возвращает копиюselfзаданной длины, дополненную слева заданной другой строкой.
Кодировка
-
b: Возвращает копиюselfс кодировкой ASCII-8BIT. -
scrub: Возвращает копиюself, в которой каждый недопустимый байт заменён заданным символом. -
unicode_normalize: Возвращает копиюself, в которой каждый символ нормализован по Unicode. -
encode: Возвращает копиюself, в которой все символы преобразованы из одной кодировки в другую.
Замена
-
dump: Возвращает печатное представлениеself, заключённое в двойные кавычки. -
undump: Обратная операция дляdump; возвращает копиюself, в которой отменены изменения, подобные тем, что выполняетdump. -
sub: Возвращает копиюself, в которой первая подстрока, соответствующая заданному шаблону, заменена заданной строкой-заменой. -
gsub: Возвращает копиюself, в которой каждая подстрока, соответствующая заданному шаблону, заменена заданной строкой-заменой. -
succ(также известен какnext): Возвращает строку, следующую заself. -
reverse: Возвращает копиюselfс символами в обратном порядке. -
tr: Возвращает копиюself, в которой указанные символы заменены указанными символами-заменами. -
tr_s: Возвращает копиюself, в которой указанные символы заменены указанными символами-заменами, а из изменённых подстрок удалены дубликаты. -
%: Возвращает строку, полученную в результате форматирования заданного объекта вself.
Регистр
-
capitalize: Возвращает копиюself, в которой первый символ переведён в верхний регистр, а все остальные — в нижний. -
downcase: Возвращает копиюself, в которой все символы переведены в нижний регистр. -
upcase: Возвращает копиюself, в которой все символы переведены в верхний регистр. -
swapcase: Возвращает копиюself, в которой все символы в верхнем регистре переведены в нижний, а все символы в нижнем регистре — в верхний.
Удаление
-
delete: Возвращает копиюselfс удалёнными символами. -
delete_prefix: Возвращает копиюselfс удалённым заданным префиксом. -
delete_suffix: Возвращает копиюselfс удалённым заданным суффиксом. -
lstrip: Возвращает копиюselfс удалёнными начальными пробельными символами. -
rstrip: Возвращает копиюselfс удалёнными конечными пробельными символами. -
strip: Возвращает копиюselfс удалёнными начальными и конечными пробельными символами. -
chomp: Возвращает копиюselfс удалённым конечным разделителем записей, если он найден. -
chop: Возвращает копиюselfс удалёнными конечными символами новой строки или последним символом. -
squeeze: Возвращает копиюselfс удалёнными подряд идущими повторяющимися символами. -
[](также известен какslice): Возвращает подстроку, определяемую заданным индексом, начальной позицией и длиной, диапазоном, регулярным выражением или строкой. -
byteslice: Возвращает подстроку, определяемую заданным индексом, начальной позицией и длиной или диапазоном. -
chr: Возвращает первый символ.
Дублирование
-
to_s(также известен какto_str): Еслиselfявляется подклассомString, возвращаетself, скопированную вString; в противном случае возвращаетself.
Преобразование в объект не типа String
Каждый из этих методов преобразует содержимое self в объект не типа String.
Символы, байты и кластеры
-
bytes: Возвращает массив байтов вself. -
chars: Возвращает массив символов вself. -
codepoints: Возвращает массив целочисленных кодовых точек вself. -
getbyte: Возвращает целочисленное значение байта по заданному индексу вself. -
grapheme_clusters: Возвращает массив графемных кластеров вself.
Разбиение
-
lines: Возвращает массив строк вself, определяемых заданным разделителем записей. -
partition: Возвращает массив из 3 элементов, определяемый первой подстрокой, соответствующей заданной подстроке или регулярному выражению. -
rpartition: Возвращает массив из 3 элементов, определяемый последней подстрокой, соответствующей заданной подстроке или регулярному выражению. -
split: Возвращает массив подстрок, разделённых заданным разделителем — регулярным выражением или строкой, — либо передаёт эти подстроки блоку, если он задан.
Сопоставление
-
scan: Возвращает массив подстрок, соответствующих заданному регулярному выражению или строке, либо передаёт каждую совпавшую подстроку блоку, если он задан. -
unpack: Возвращает массив подстрок, извлечённых изselfсогласно заданному формату. -
unpack1: Возвращает первую подстроку, извлечённую изselfсогласно заданному формату.
Числовые значения
-
hex: Возвращает целочисленное значение начальных символов, интерпретируемых как шестнадцатеричные цифры. -
oct: Возвращает целочисленное значение начальных символов, интерпретируемых как восьмеричные цифры. -
ord: Возвращает целочисленный код первой буквы вself. -
to_c: Возвращает комплексное значение начальных символов, интерпретируемых как комплексное число. -
to_i: Возвращает целочисленное значение начальных символов, интерпретируемых как целое число. -
to_f: Возвращает значение с плавающей точкой начальных символов, интерпретируемых как число с плавающей точкой. -
to_r: Возвращает рациональное значение начальных символов, интерпретируемых как рациональное число.
Строки и символы
-
inspect: Возвращает копиюself, заключённую в двойные кавычки, со специальными символами, представленными escape-последовательностями. -
intern(также доступен под именемto_sym): Возвращает символ, соответствующийself.
Итерация
-
each_byte: Вызывает заданный блок для каждого следующего байта вself. -
each_char: Вызывает заданный блок для каждого следующего символа вself. -
each_codepoint: Вызывает заданный блок для каждой следующей целочисленной кодовой точки вself. -
each_grapheme_cluster: Вызывает заданный блок для каждого следующего графемного кластера вself. -
each_line: Вызывает заданный блок для каждой следующей строки вself, определяемой заданным разделителем записей. -
upto: Вызывает заданный блок для каждого строкового значения, возвращаемого последовательными вызовамиsucc.
Открытые методы класса
# File ext/json/lib/json/add/string.rb, line 11
def self.json_create(object)
object["raw"].pack("C*")
end 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 (!UNDEF_P(venc) && !NIL_P(venc)) {
enc = rb_to_encoding(venc);
}
if (!UNDEF_P(vcapa) && !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) || FL_TEST(str, STR_SHARED|STR_NOFREE)) {
/* make noembed always */
const size_t size = (size_t)capa + termlen;
const char *const old_ptr = RSTRING_PTR(str);
const size_t osize = RSTRING_LEN(str) + TERM_LEN(str);
char *new_ptr = ALLOC_N(char, size);
if (STR_EMBED_P(str)) RUBY_ASSERT((long)osize <= str_embed_capa(str));
memcpy(new_ptr, old_ptr, osize < size ? osize : size);
FL_UNSET_RAW(str, STR_SHARED|STR_NOFREE);
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));
}
STR_SET_LEN(str, 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, содержащий заданную string.
Параметр options — это необязательные именованные параметры (см. ниже).
Если аргумент не задан и именованный параметр encoding также не задан, возвращается пустая строка с ASCII-8BIT Encoding:
s = String.new # => "" s.encoding # => #<Encoding:ASCII-8BIT>
Если задан аргумент string, а именованный параметр encoding не задан, возвращается новая строка с той же кодировкой, что и у string:
s0 = 'foo'.encode(Encoding::UTF_16) s1 = String.new(s0) s1.encoding # => #<Encoding:UTF-16 (dummy)>
(В отличие от String.new, строковый литерал, например '', или литерал here-документа всегда имеет кодировку скрипта.)
Если задан именованный параметр encoding, возвращается строка с указанной кодировкой; encoding может быть объектом Encoding, названием кодировки или псевдонимом её названия:
String.new(encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII>
String.new('', encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII>
String.new('foo', encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII>
String.new('foo', encoding: 'US-ASCII').encoding # => #<Encoding:US-ASCII>
String.new('foo', encoding: 'ASCII').encoding # => #<Encoding:US-ASCII>
Указанная кодировка не обязана соответствовать содержимому строки, и её соответствие не проверяется:
s = String.new('こんにちは', encoding: 'ascii')
s.valid_encoding? # => false
Однако сам параметр encoding проверяется:
String.new('foo', encoding: 'bar') # Raises ArgumentError.
Если задан именованный параметр capacity, указанное значение носит рекомендательный характер и может как повлиять, так и не повлиять на размер внутреннего буфера, что, в свою очередь, может сказаться на производительности:
String.new('foo', capacity: 1) # Buffer size is at least 4 (includes terminal null byte).
String.new('foo', capacity: 4096) # Buffer size is at least 4;
# may be equal to, greater than, or less than 4096.
static VALUE
rb_str_s_try_convert(VALUE dummy, VALUE str)
{
return rb_check_string_type(str);
} Пытается преобразовать заданный object в строку.
Если object уже является строкой, возвращает object без изменений.
В противном случае, если object отвечает на :to_str, вызывает object.to_str и возвращает результат.
Возвращает nil, если object не отвечает на :to_str.
Вызывает исключение, если object.to_str не возвращает строку.
Открытые методы экземпляра
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 (см. Спецификации формата):
'%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_embed(rb_cString, 0);
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) {
if (STR_EMBEDDABLE_P(len, 1)) {
str2 = str_alloc_embed(rb_cString, len + 1);
memset(RSTRING_PTR(str2), 0, len + 1);
}
else {
str2 = str_alloc_heap(rb_cString);
RSTRING(str2)->as.heap.aux.capa = len;
RSTRING(str2)->as.heap.ptr = ZALLOC_N(char, (size_t)len + 1);
}
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_enc_new(rb_cString, 0, len, STR_ENC_GET(str));
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;
} Возвращает новую строку, содержащую n копий self:
'Ho!' * 3 # => "Ho!Ho!Ho!" 'No!' * 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_enc_new(rb_cString, 0, len1+len2, enc);
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) || CHILLED_STRING_P(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);
} Возвращает замороженную строку, равную self.
Возвращённая строка является self тогда и только тогда, когда выполняются все следующие условия:
-
selfуже заморожена. -
selfявляется экземпляром String (а не экземпляром подкласса String) -
У
selfне заданы переменные экземпляра.
В противном случае возвращённая строка является замороженной копией self.
Возврат self, когда это возможно, позволяет избежать дублирования self; см. дедупликацию данных.
Это также может помочь избежать дублирования других уже существующих строк:
s0 = 'foo' s1 = 'foo' s0.object_id == s1.object_id # => false (-s0).object_id == (-s1).object_id # => true
Обратите внимание, что метод -@ удобно использовать для определения константы:
FileName = -'config/database.yml'
А его псевдоним dedup лучше подходит для цепочек вызовов:
'foo'.dedup.gsub!('o')
Связанный раздел: см. Замораживание и размораживание.
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_ascii8bit_appendable_encoding_index(enc, code);
if (encidx >= 0) {
rb_str_buf_cat_byte(str1, (unsigned char)code);
}
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;
}
else if (cr == ENC_CODERANGE_BROKEN) {
cr = ENC_CODERANGE_UNKNOWN;
}
ENC_CODERANGE_SET(str1, cr);
}
return str1;
} Добавляет строковое представление object к self; возвращает self.
Если object — строка, добавляет её к self:
s = 'foo' s << 'bar' # => "foobar" s # => "foobar"
Если object — целое число, его значение считается кодовой точкой; преобразует значение в символ перед конкатенацией:
s = 'foo' s << 33 # => "foo!"
Кроме того, если кодовая точка находится в диапазоне 0..0xff, а кодировка self — Encoding::US_ASCII, кодировка меняется на Encoding::ASCII_8BIT:
s = 'foo'.encode(Encoding::US_ASCII) s.encoding # => #<Encoding:US-ASCII> s << 0xff # => "foo\xFF" s.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
Вызывает исключение RangeError, если эта кодовая точка не представима в кодировке self:
s = 'foo' s.encoding # => <Encoding:UTF-8> s << 0x00110000 # 1114112 out of char range (RangeError) s = 'foo'.encode(Encoding::EUC_JP) s << 0x00800080 # invalid codepoint 0x800080 in EUC-JP (RangeError)
Связанный раздел: см. Изменение.
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, оценивая их содержимое, а не длину.
Возвращает:
-
-1, еслиselfменьше. -
0, если они равны. -
1, еслиselfбольше. -
nil, если их невозможно сравнить.
Примеры:
'a' <=> 'b' # => -1 'a' <=> 'ab' # => -1 'a' <=> 'a' # => 0 'b' <=> 'a' # => 1 'ab' <=> 'a' # => 1 'a' <=> :a # => nil
Класс String включает модуль Comparable; каждый его метод использует String#<=> для сравнения.
Связанный раздел: см. Сравнение.
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);
} Возвращает признак того, равно ли object значению self.
Если object — строка, возвращает признак того, что object имеет ту же длину и содержимое, что и self:
s = 'foo' s == 'foo' # => true s == 'food' # => false s == 'FOO' # => false
Возвращает false, если кодировки двух строк несовместимы:
"\u{e4 f6 fc}".encode(Encoding::ISO_8859_1) == ("\u{c4 d6 dc}") # => false
Если object не является строкой:
-
Если
objectподдерживает методto_str, вызываетсяobject == selfи возвращается его значение. -
Если
objectне поддерживаетto_str, возвращаетсяfalse.
Связанный раздел: Сравнение.
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);
}
} Если object является Regexp, возвращает индекс первой подстроки в self, соответствующей object, или nil, если совпадение не найдено; обновляет глобальные переменные, связанные с Regexp:
'foo' =~ /f/ # => 0 $~ # => #<MatchData "f"> 'foo' =~ /o/ # => 1 $~ # => #<MatchData "o"> 'foo' =~ /x/ # => nil $~ # => nil
Обратите внимание, что string =~ regexp отличается от regexp =~ string (см. Regexp#=~):
number = nil 'no. 9' =~ /(?<number>\d+)/ # => 4 number # => nil # Not assigned. /(?<number>\d+)/ =~ 'no. 9' # => 4 number # => "9" # Assigned.
Если object не является Regexp, возвращает значение, возвращённое object =~ self.
Связанный раздел: см. Запросы.
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 {
return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
}
}
rb_check_arity(argc, 1, 2);
return rb_str_aref(str, argv[0]);
} Возвращает подстроку self, заданную аргументами.
Форма self[index]
Если задан неотрицательный целочисленный аргумент index, возвращает односимвольную подстроку self с индексом символа, равным index:
'hello'[0] # => "h" 'hello'[4] # => "o" 'hello'[5] # => nil 'Привет'[2] # => "и" 'こんにちは'[4] # => "は"
Если задан отрицательный целочисленный аргумент index, отсчёт ведётся с конца self:
'hello'[-1] # => "o" 'hello'[-5] # => "h" 'hello'[-6] # => nil
Форма self[start, length]
Если заданы целочисленные аргументы start и length, возвращает подстроку размером length символов (если они доступны), начиная с позиции символа, заданной start.
Если аргумент start неотрицательный, смещение равно start:
'hello'[0, 1] # => "h" 'hello'[0, 5] # => "hello" 'hello'[0, 6] # => "hello" 'hello'[2, 3] # => "llo" 'hello'[2, 0] # => "" 'hello'[2, -1] # => nil
Если аргумент start отрицательный, отсчёт ведётся с конца self:
'hello'[-1, 1] # => "o" 'hello'[-5, 5] # => "hello" 'hello'[-1, 0] # => "" 'hello'[-6, 5] # => nil
Особый случай: если start равно длине self, возвращает новую пустую строку:
'hello'[5, 3] # => ""
Форма self[range]
Если задан аргумент Range range, формирует подстроку self[range.start, range.size]:
'hello'[0..2] # => "hel" 'hello'[0, 3] # => "hel" 'hello'[0...2] # => "he" 'hello'[0, 2] # => "he" 'hello'[0, 0] # => "" 'hello'[0...0] # => ""
Форма self[regexp, capture = 0]
Если задан аргумент Regexp regexp и capture равен нулю, выполняет поиск соответствующей подстроки в self; обновляет глобальные переменные, связанные с Regexp:
'hello'[/ell/] # => "ell" 'hello'[/l+/] # => "ll" 'hello'[//] # => "" 'hello'[/nosuch/] # => nil
Если capture — положительное целое число n, возвращает группу совпадения номер +n+:
'hello'[/(h)(e)(l+)(o)/] # => "hello" 'hello'[/(h)(e)(l+)(o)/, 1] # => "h" $1 # => "h" 'hello'[/(h)(e)(l+)(o)/, 2] # => "e" $2 # => "e" 'hello'[/(h)(e)(l+)(o)/, 3] # => "ll" 'hello'[/(h)(e)(l+)(o)/, 4] # => "o" 'hello'[/(h)(e)(l+)(o)/, 5] # => nil
Форма self[substring]
Если задан строковый аргумент substring, возвращает соответствующую подстроку self, если она найдена:
'hello'['ell'] # => "ell" 'hello'[''] # => "" 'hello'['nosuch'] # => nil 'Привет'['ив'] # => "ив" 'こんにちは'['んにち'] # => "んにち"
Связанный раздел: см. Преобразование в новую строку.
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_update(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]);
} Возвращает self, заменив всё его содержимое, подстроку или ничего; возвращает аргумент other_string.
Форма self[index] = other_string
Если задан неотрицательный целочисленный аргумент index, выполняется поиск односимвольной подстроки в self со смещением index:
s = 'hello' s[0] = 'foo' # => "foo" s # => "fooello" s = 'hello' s[4] = 'foo' # => "foo" s # => "hellfoo" s = 'hello' s[5] = 'foo' # => "foo" s # => "hellofoo" s = 'hello' s[6] = 'foo' # Raises IndexError: index 6 out of string.
Если задан отрицательный целочисленный аргумент index, отсчёт ведётся от конца self:
s = 'hello' s[-1] = 'foo' # => "foo" s # => "hellfoo" s = 'hello' s[-5] = 'foo' # => "foo" s # => "fooello" s = 'hello' s[-6] = 'foo' # Raises IndexError: index -6 out of string.
Форма self[start, length] = other_string
Если заданы целочисленные аргументы start и length, выполняется поиск подстроки размером length символов (если доступно), начиная со смещения, заданного аргументом start.
Если аргумент start неотрицательный, смещение равно start:
s = 'hello' s[0, 1] = 'foo' # => "foo" s # => "fooello" s = 'hello' s[0, 5] = 'foo' # => "foo" s # => "foo" s = 'hello' s[0, 9] = 'foo' # => "foo" s # => "foo" s = 'hello' s[2, 0] = 'foo' # => "foo" s # => "hefoollo" s = 'hello' s[2, -1] = 'foo' # Raises IndexError: negative length -1.
Если аргумент start отрицательный, отсчёт ведётся от конца self:
s = 'hello' s[-1, 1] = 'foo' # => "foo" s # => "hellfoo" s = 'hello' s[-1, 9] = 'foo' # => "foo" s # => "hellfoo" s = 'hello' s[-5, 2] = 'foo' # => "foo" s # => "foollo" s = 'hello' s[-3, 0] = 'foo' # => "foo" s # => "hefoollo" s = 'hello' s[-6, 2] = 'foo' # Raises IndexError: index -6 out of string.
Особый случай: если start равно длине self, аргумент добавляется в конец self:
s = 'hello' s[5, 3] = 'foo' # => "foo" s # => "hellofoo"
Форма self[range] = other_string
Если задан аргумент Range range, эквивалентно self[range.start, range.size] = other_string:
s0 = 'hello' s1 = 'hello' s0[0..2] = 'foo' # => "foo" s1[0, 3] = 'foo' # => "foo" s0 # => "foolo" s1 # => "foolo" s = 'hello' s[0...2] = 'foo' # => "foo" s # => "foollo" s = 'hello' s[0...0] = 'foo' # => "foo" s # => "foohello" s = 'hello' s[9..10] = 'foo' # Raises RangeError: 9..10 out of range
Форма self[regexp, capture = 0] = other_string
Если задан аргумент Regexp regexp и capture равно нулю, выполняется поиск соответствующей подстроки в self; обновляются глобальные переменные, связанные с Regexp:
s = 'hello' s[/l/] = 'L' # => "L" [$`, $&, $'] # => ["he", "l", "lo"] s[/eLlo/] = 'owdy' # => "owdy" [$`, $&, $'] # => ["h", "eLlo", ""] s[/eLlo/] = 'owdy' # Raises IndexError: regexp not matched. [$`, $&, $'] # => [nil, nil, nil]
Если capture — положительное целое число n, выполняется поиск n-й совпавшей группы:
s = 'hello' s[/(h)(e)(l+)(o)/] = 'foo' # => "foo" [$`, $&, $'] # => ["", "hello", ""] s = 'hello' s[/(h)(e)(l+)(o)/, 1] = 'foo' # => "foo" s # => "fooello" [$`, $&, $'] # => ["", "hello", ""] s = 'hello' s[/(h)(e)(l+)(o)/, 2] = 'foo' # => "foo" s # => "hfoollo" [$`, $&, $'] # => ["", "hello", ""] s = 'hello' s[/(h)(e)(l+)(o)/, 4] = 'foo' # => "foo" s # => "hellfoo" [$`, $&, $'] # => ["", "hello", ""] s = 'hello' # => "hello" s[/(h)(e)(l+)(o)/, 5] = 'foo # Raises IndexError: index 5 out of regexp. s = 'hello' s[/nosuch/] = 'foo' # Raises IndexError: regexp not matched.
Форма self[substring] = other_string
Если задан строковый аргумент substring:
s = 'hello' s['l'] = 'foo' # => "foo" s # => "hefoolo" s = 'hello' s['ll'] = 'foo' # => "foo" s # => "hefooo" s = 'Привет' s['ив'] = 'foo' # => "foo" s # => "Прfooет" s = 'こんにちは' s['んにち'] = 'foo' # => "foo" s # => "こfooは" s['nosuch'] = 'foo' # Raises IndexError: string not matched.
Связанные разделы: см. Изменение.
VALUE
rb_str_append_as_bytes(int argc, VALUE *argv, VALUE str)
{
long needed_capacity = 0;
volatile VALUE t0;
enum ruby_value_type *types = ALLOCV_N(enum ruby_value_type, t0, argc);
for (int index = 0; index < argc; index++) {
VALUE obj = argv[index];
enum ruby_value_type type = types[index] = rb_type(obj);
switch (type) {
case T_FIXNUM:
case T_BIGNUM:
needed_capacity++;
break;
case T_STRING:
needed_capacity += RSTRING_LEN(obj);
break;
default:
rb_raise(
rb_eTypeError,
"wrong argument type %"PRIsVALUE" (expected String or Integer)",
rb_obj_class(obj)
);
break;
}
}
str_ensure_available_capa(str, needed_capacity);
char *sptr = RSTRING_END(str);
for (int index = 0; index < argc; index++) {
VALUE obj = argv[index];
enum ruby_value_type type = types[index];
switch (type) {
case T_FIXNUM:
case T_BIGNUM: {
argv[index] = obj = rb_int_and(obj, INT2FIX(0xff));
char byte = (char)(NUM2INT(obj) & 0xFF);
*sptr = byte;
sptr++;
break;
}
case T_STRING: {
const char *ptr;
long len;
RSTRING_GETMEM(obj, ptr, len);
memcpy(sptr, ptr, len);
sptr += len;
break;
}
default:
rb_bug("append_as_bytes arguments should have been validated");
}
}
STR_SET_LEN(str, RSTRING_LEN(str) + needed_capacity);
TERM_FILL(sptr, TERM_LEN(str)); /* sentinel */
int cr = ENC_CODERANGE(str);
switch (cr) {
case ENC_CODERANGE_7BIT: {
for (int index = 0; index < argc; index++) {
VALUE obj = argv[index];
enum ruby_value_type type = types[index];
switch (type) {
case T_FIXNUM:
case T_BIGNUM: {
if (!ISASCII(NUM2INT(obj))) {
goto clear_cr;
}
break;
}
case T_STRING: {
if (ENC_CODERANGE(obj) != ENC_CODERANGE_7BIT) {
goto clear_cr;
}
break;
}
default:
rb_bug("append_as_bytes arguments should have been validated");
}
}
break;
}
case ENC_CODERANGE_VALID:
if (ENCODING_GET_INLINED(str) == ENCINDEX_ASCII_8BIT) {
goto keep_cr;
}
else {
goto clear_cr;
}
break;
default:
goto clear_cr;
break;
}
RB_GC_GUARD(t0);
clear_cr:
// If no fast path was hit, we clear the coderange.
// append_as_bytes is predominantly meant to be used in
// buffering situation, hence it's likely the coderange
// will never be scanned, so it's not worth spending time
// precomputing the coderange except for simple and common
// situations.
ENC_CODERANGE_CLEAR(str);
keep_cr:
return str;
} Объединяет каждый объект из objects с self; возвращает self; не выполняет проверку или преобразование кодировки:
s = 'foo'
s.append_as_bytes(" \xE2\x82") # => "foo \xE2\x82"
s.valid_encoding? # => false
s.append_as_bytes("\xAC 12")
s.valid_encoding? # => true
Если заданный объект — целое число, его значение рассматривается как 8-битный байт; если целое число занимает больше одного байта (то есть больше 255), добавляется только младший байт (аналогично String#setbyte):
s = "" s.append_as_bytes(0, 257) # => "\u0000\u0001" s.bytesize # => 2
Связанные разделы: см. Изменение.
static VALUE
rb_str_is_ascii_only_p(VALUE str)
{
int cr = rb_enc_str_coderange(str);
return RBOOL(cr == ENC_CODERANGE_7BIT);
} Возвращает, содержит ли self только символы ASCII:
'abc'.ascii_only? # => true
"abc\u{6666}".ascii_only? # => false
Связанные разделы: см. Запросы.
static VALUE
rb_str_b(VALUE str)
{
VALUE str2;
if (STR_EMBED_P(str)) {
str2 = str_alloc_embed(rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
}
else {
str2 = str_alloc_heap(rb_cString);
}
str_replace_shared_without_enc(str2, str);
if (rb_enc_asciicompat(STR_ENC_GET(str))) {
// BINARY strings can never be broken; they're either 7-bit ASCII or VALID.
// If we know the receiver's code range then we know the result's code range.
int cr = ENC_CODERANGE(str);
switch (cr) {
case ENC_CODERANGE_7BIT:
ENC_CODERANGE_SET(str2, ENC_CODERANGE_7BIT);
break;
case ENC_CODERANGE_BROKEN:
case ENC_CODERANGE_VALID:
ENC_CODERANGE_SET(str2, ENC_CODERANGE_VALID);
break;
default:
ENC_CODERANGE_CLEAR(str2);
break;
}
}
return str2;
} Возвращает копию self с кодировкой ASCII-8BIT; исходные байты не изменяются:
s = "\x99" s.encoding # => #<Encoding:UTF-8> t = s.b # => "\x99" t.encoding # => #<Encoding:ASCII-8BIT> s = "\u4095" # => "䂕" s.encoding # => #<Encoding:UTF-8> s.bytes # => [228, 130, 149] t = s.b # => "\xE4\x82\x95" t.encoding # => #<Encoding:ASCII-8BIT> t.bytes # => [228, 130, 149]
Связанные разделы: см. Преобразование в новую строку.
static VALUE
rb_str_byteindex_m(int argc, VALUE *argv, VALUE str)
{
VALUE sub;
VALUE initpos;
long pos;
if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
long slen = RSTRING_LEN(str);
pos = NUM2LONG(initpos);
if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
if (RB_TYPE_P(sub, T_REGEXP)) {
rb_backref_set(Qnil);
}
return Qnil;
}
}
else {
pos = 0;
}
str_ensure_byte_pos(str, pos);
if (RB_TYPE_P(sub, T_REGEXP)) {
if (rb_reg_search(sub, str, pos, 0) >= 0) {
VALUE match = rb_backref_get();
struct re_registers *regs = RMATCH_REGS(match);
pos = BEG(0);
return LONG2NUM(pos);
}
}
else {
StringValue(sub);
pos = rb_str_byteindex(str, sub, pos);
if (pos >= 0) return LONG2NUM(pos);
}
return Qnil;
} Возвращает целочисленный индекс подстроки в self, отсчитываемый от нуля и задаваемый аргументами object (строкой или Regexp) и offset, либо nil, если такой подстроки нет; возвращаемый индекс — это количество байтов (не символов).
Если object — строка, возвращается индекс первой найденной подстроки, равной object:
s = 'foo' # => "foo"
s.size # => 3 # Three 1-byte characters.
s.bytesize # => 3 # Three bytes.
s.byteindex('f') # => 0
s.byteindex('o') # => 1
s.byteindex('oo') # => 1
s.byteindex('ooo') # => nil
Если object — Regexp, возвращается индекс первой найденной подстроки, соответствующей object; обновляются глобальные переменные, связанные с Regexp:
s = 'foo' s.byteindex(/f/) # => 0 $~ # => #<MatchData "f"> s.byteindex(/o/) # => 1 s.byteindex(/oo/) # => 1 s.byteindex(/ooo/) # => nil $~ # => nil
Целочисленный аргумент offset, если задан, определяет индекс байта (отсчитываемый от нуля), с которого начинается поиск.
Если offset неотрицательный, поиск начинается с позиции байта offset:
s = 'foo'
s.byteindex('o', 1) # => 1
s.byteindex('o', 2) # => 2
s.byteindex('o', 3) # => nil
Если offset отрицательный, отсчёт ведётся от конца self:
s = 'foo'
s.byteindex('o', -1) # => 2
s.byteindex('o', -2) # => 1
s.byteindex('o', -3) # => 1
s.byteindex('o', -4) # => nil
Вызывает IndexError, если байт в позиции offset не является первым байтом символа:
s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
s.size # => 2 # Two 3-byte characters.
s.bytesize # => 6 # Six bytes.
s.byteindex("\uFFFF") # => 0
s.byteindex("\uFFFF", 1) # Raises IndexError
s.byteindex("\uFFFF", 2) # Raises IndexError
s.byteindex("\uFFFF", 3) # => 3
s.byteindex("\uFFFF", 4) # Raises IndexError
s.byteindex("\uFFFF", 5) # Raises IndexError
s.byteindex("\uFFFF", 6) # => nil
Связанные разделы: см. Запросы.
static VALUE
rb_str_byterindex_m(int argc, VALUE *argv, VALUE str)
{
VALUE sub;
VALUE initpos;
long pos, len = RSTRING_LEN(str);
if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
pos = NUM2LONG(initpos);
if (pos < 0 && (pos += len) < 0) {
if (RB_TYPE_P(sub, T_REGEXP)) {
rb_backref_set(Qnil);
}
return Qnil;
}
if (pos > len) pos = len;
}
else {
pos = len;
}
str_ensure_byte_pos(str, pos);
if (RB_TYPE_P(sub, T_REGEXP)) {
if (rb_reg_search(sub, str, pos, 1) >= 0) {
VALUE match = rb_backref_get();
struct re_registers *regs = RMATCH_REGS(match);
pos = BEG(0);
return LONG2NUM(pos);
}
}
else {
StringValue(sub);
pos = rb_str_byterindex(str, sub, pos);
if (pos >= 0) return LONG2NUM(pos);
}
return Qnil;
} Возвращает целочисленный индекс подстроки в self, которая является последним совпадением для заданных object (строки или Regexp) и offset, либо nil, если такой подстроки нет; возвращаемый индекс — это количество байтов (не символов).
Если object — строка, возвращается индекс последней найденной подстроки, равной object:
s = 'foo' # => "foo"
s.size # => 3 # Three 1-byte characters.
s.bytesize # => 3 # Three bytes.
s.byterindex('f') # => 0
s.byterindex('o') # => 2
s.byterindex('oo') # => 1
s.byterindex('ooo') # => nil
Если object — Regexp, возвращается индекс последней найденной подстроки, соответствующей object; обновляются глобальные переменные, связанные с Regexp:
s = 'foo' s.byterindex(/f/) # => 0 $~ # => #<MatchData "f"> s.byterindex(/o/) # => 2 s.byterindex(/oo/) # => 1 s.byterindex(/ooo/) # => nil $~ # => nil
Последнее совпадение означает совпадение, начинающееся в самой поздней возможной позиции, а не последнее среди самых длинных совпадений:
s = 'foo' s.byterindex(/o+/) # => 2 $~ #=> #<MatchData "o">
Чтобы получить последнее самое длинное совпадение, используйте отрицательный просмотр назад:
s = 'foo' s.byterindex(/(?<!o)o+/) # => 1 $~ # => #<MatchData "oo">
Или используйте метод byteindex с отрицательным просмотром вперёд:
s = 'foo' s.byteindex(/o+(?!.*o)/) # => 1 $~ #=> #<MatchData "oo">
Целочисленный аргумент offset, если задан, определяет индекс байта (отсчитываемый от нуля), на котором заканчивается поиск.
Если offset неотрицательный, поиск заканчивается на позиции байта offset:
s = 'foo'
s.byterindex('o', 0) # => nil
s.byterindex('o', 1) # => 1
s.byterindex('o', 2) # => 2
s.byterindex('o', 3) # => 2
Если offset отрицательный, отсчёт ведётся от конца self:
s = 'foo'
s.byterindex('o', -1) # => 2
s.byterindex('o', -2) # => 1
s.byterindex('o', -3) # => nil
Вызывает IndexError, если байт в позиции offset не является первым байтом символа:
s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
s.size # => 2 # Two 3-byte characters.
s.bytesize # => 6 # Six bytes.
s.byterindex("\uFFFF") # => 3
s.byterindex("\uFFFF", 1) # Raises IndexError
s.byterindex("\uFFFF", 2) # Raises IndexError
s.byterindex("\uFFFF", 3) # => 3
s.byterindex("\uFFFF", 4) # Raises IndexError
s.byterindex("\uFFFF", 5) # Raises IndexError
s.byterindex("\uFFFF", 6) # => nil
Связанные разделы: см. Запросы.
static VALUE
rb_str_bytes(VALUE str)
{
VALUE ary = WANTARRAY("bytes", RSTRING_LEN(str));
return rb_str_enumerate_bytes(str, ary);
} Возвращает массив байтов в self:
'hello'.bytes # => [104, 101, 108, 108, 111] 'Привет'.bytes # => [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130] 'こんにちは'.bytes # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
Связанные разделы: см. Преобразование в нестроковое значение.
VALUE
rb_str_bytesize(VALUE str)
{
return LONG2NUM(RSTRING_LEN(str));
} Возвращает количество байтов в self.
Обратите внимание, что количество байтов может отличаться от количества символов (возвращаемого методом size):
s = 'foo' s.bytesize # => 3 s.size # => 3 s = 'Привет' s.bytesize # => 12 s.size # => 6 s = 'こんにちは' s.bytesize # => 15 s.size # => 5
Связанные разделы: см. Запросы.
static VALUE
rb_str_byteslice(int argc, VALUE *argv, VALUE str)
{
if (argc == 2) {
long beg = NUM2LONG(argv[0]);
long len = NUM2LONG(argv[1]);
return str_byte_substr(str, beg, len, TRUE);
}
rb_check_arity(argc, 1, 2);
return str_byte_aref(str, argv[0]);
} Возвращает подстроку из self или nil, если подстроку невозможно создать.
Если заданы целочисленные аргументы offset и length, возвращается подстрока, начинающаяся с заданного offset и имеющая заданную length (если доступно):
s = '0123456789' # => "0123456789" s.byteslice(2) # => "2" s.byteslice(200) # => nil s.byteslice(4, 3) # => "456" s.byteslice(4, 30) # => "456789"
Возвращает nil, если length отрицательный или offset выходит за пределы self:
s.byteslice(4, -1) # => nil s.byteslice(40, 2) # => nil
Если offset отрицательный, отсчёт ведётся от конца self:
s = '0123456789' # => "0123456789" s.byteslice(-4) # => "6" s.byteslice(-4, 3) # => "678"
Если задан аргумент Range range, возвращается byteslice(range.begin, range.size):
s = '0123456789' # => "0123456789" s.byteslice(4..6) # => "456" s.byteslice(-6..-4) # => "456" s.byteslice(5..2) # => "" # range.size is zero. s.byteslice(40..42) # => nil
Начальное и конечное смещения не обязаны совпадать с границами символов:
s = 'こんにちは' s.byteslice(0, 3) # => "こ" s.byteslice(1, 3) # => "\x81\x93\xE3"
Кодировки self и возвращаемой подстроки всегда совпадают:
s.encoding # => #<Encoding:UTF-8> s.byteslice(0, 3).encoding # => #<Encoding:UTF-8> s.byteslice(1, 3).encoding # => #<Encoding:UTF-8>
Однако в зависимости от границ символов кодировка возвращаемой подстроки может быть недопустимой:
s.valid_encoding? # => true s.byteslice(0, 3).valid_encoding? # => true s.byteslice(1, 3).valid_encoding? # => false
Связанные разделы: см. Преобразование в новую строку.
static VALUE
rb_str_bytesplice(int argc, VALUE *argv, VALUE str)
{
long beg, len, vbeg, vlen;
VALUE val;
int cr;
rb_check_arity(argc, 2, 5);
if (!(argc == 2 || argc == 3 || argc == 5)) {
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
}
if (argc == 2 || (argc == 3 && !RB_INTEGER_TYPE_P(argv[0]))) {
if (!rb_range_beg_len(argv[0], &beg, &len, RSTRING_LEN(str), 2)) {
rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
rb_builtin_class_name(argv[0]));
}
val = argv[1];
StringValue(val);
if (argc == 2) {
/* bytesplice(range, str) */
vbeg = 0;
vlen = RSTRING_LEN(val);
}
else {
/* bytesplice(range, str, str_range) */
if (!rb_range_beg_len(argv[2], &vbeg, &vlen, RSTRING_LEN(val), 2)) {
rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
rb_builtin_class_name(argv[2]));
}
}
}
else {
beg = NUM2LONG(argv[0]);
len = NUM2LONG(argv[1]);
val = argv[2];
StringValue(val);
if (argc == 3) {
/* bytesplice(index, length, str) */
vbeg = 0;
vlen = RSTRING_LEN(val);
}
else {
/* bytesplice(index, length, str, str_index, str_length) */
vbeg = NUM2LONG(argv[3]);
vlen = NUM2LONG(argv[4]);
}
}
str_check_beg_len(str, &beg, &len);
str_check_beg_len(val, &vbeg, &vlen);
str_modify_keep_cr(str);
if (RB_UNLIKELY(ENCODING_GET_INLINED(str) != ENCODING_GET_INLINED(val))) {
rb_enc_associate(str, rb_enc_check(str, val));
}
rb_str_update_1(str, beg, len, val, vbeg, vlen);
cr = ENC_CODERANGE_AND(ENC_CODERANGE(str), ENC_CODERANGE(val));
if (cr != ENC_CODERANGE_BROKEN)
ENC_CODERANGE_SET(str, cr);
return str;
} Заменяет целевые байты в self на исходные байты из заданной строки str; возвращает self.
В первой форме аргументы offset и length задают целевые байты, а исходными байтами служат все байты заданного str:
'0123456789'.bytesplice(0, 3, 'abc') # => "abc3456789" '0123456789'.bytesplice(3, 3, 'abc') # => "012abc6789" '0123456789'.bytesplice(0, 50, 'abc') # => "abc" '0123456789'.bytesplice(50, 3, 'abc') # Raises IndexError.
Количество целевых и исходных байтов может различаться:
'0123456789'.bytesplice(0, 6, 'abc') # => "abc6789" # Shorter source. '0123456789'.bytesplice(0, 1, 'abc') # => "abc123456789" # Shorter target.
Любое из этих количеств может быть равно нулю (то есть задавать пустую строку):
'0123456789'.bytesplice(0, 3, '') # => "3456789" # Empty source. '0123456789'.bytesplice(0, 0, 'abc') # => "abc0123456789" # Empty target.
Во второй форме, как и в первой, аргументы offset и length задают целевые байты; аргумент str содержит исходные байты, а дополнительные аргументы str_offset и str_length задают фактические исходные байты:
'0123456789'.bytesplice(0, 3, 'abc', 0, 3) # => "abc3456789" '0123456789'.bytesplice(0, 3, 'abc', 1, 1) # => "b3456789" # Shorter source. '0123456789'.bytesplice(0, 1, 'abc', 0, 3) # => "abc123456789" # Shorter target. '0123456789'.bytesplice(0, 3, 'abc', 1, 0) # => "3456789" # Empty source. '0123456789'.bytesplice(0, 0, 'abc', 0, 3) # => "abc0123456789" # Empty target.
В третьей форме аргумент range задаёт целевые байты, а исходными байтами служат все байты заданного str:
'0123456789'.bytesplice(0..2, 'abc') # => "abc3456789" '0123456789'.bytesplice(3..5, 'abc') # => "012abc6789" '0123456789'.bytesplice(0..5, 'abc') # => "abc6789" # Shorter source. '0123456789'.bytesplice(0..0, 'abc') # => "abc123456789" # Shorter target. '0123456789'.bytesplice(0..2, '') # => "3456789" # Empty source. '0123456789'.bytesplice(0...0, 'abc') # => "abc0123456789" # Empty target.
В четвёртой форме, как и в третьей, аргумент range задаёт целевые байты; аргумент str содержит исходные байты, а дополнительный аргумент str_range задаёт фактические исходные байты:
'0123456789'.bytesplice(0..2, 'abc', 0..2) # => "abc3456789" '0123456789'.bytesplice(3..5, 'abc', 0..2) # => "012abc6789" '0123456789'.bytesplice(0..2, 'abc', 0..1) # => "ab3456789" # Shorter source. '0123456789'.bytesplice(0..1, 'abc', 0..2) # => "abc23456789" # Shorter target. '0123456789'.bytesplice(0..2, 'abc', 0...0) # => "3456789" # Empty source. '0123456789'.bytesplice(0...0, 'abc', 0..2) # => "abc0123456789" # Empty target.
Во всех формах начала и концы исходных и целевых байтов должны находиться на границах символов.
В этих примерах self содержит пять 3-байтовых символов, поэтому границы символов находятся по смещениям 0, 3, 6, 9, 12 и 15.
'こんにちは'.bytesplice(0, 3, 'abc') # => "abcんにちは" 'こんにちは'.bytesplice(1, 3, 'abc') # Raises IndexError. 'こんにちは'.bytesplice(0, 2, 'abc') # Raises IndexError.
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;
} Возвращает строку, содержащую символы из self, регистр которых может быть изменён:
-
Первый символ переводится в верхний регистр.
-
Все остальные символы переводятся в нижний регистр.
Примеры:
'hello'.capitalize # => "Hello" 'HELLO'.capitalize # => "Hello" 'straße'.capitalize # => "Straße" # Lowercase 'ß' not changed. 'STRAẞE'.capitalize # => "Straße" # Uppercase 'ẞ' downcased to 'ß'. 'привет'.capitalize # => "Привет" 'ПРИВЕТ'.capitalize # => "Привет"
У некоторых символов (и некоторых наборов символов) нет вариантов в верхнем и нижнем регистре; см. преобразование регистра:
s = '1, 2, 3, ...' s.capitalize == s # => true s = 'こんにちは' s.capitalize == s # => true
Преобразование регистра зависит от заданного mapping, которым может быть :ascii, :fold или :turkic; см. преобразования регистра.
Связанные методы: см. Преобразование в новую строку.
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;
} Как String#capitalize, но:
-
Изменяет регистр символов в
self(а не в копииself). -
Возвращает
self, если были внесены изменения, и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, если
self.downcaseменьшеother_string.downcase. -
0, если они равны.
-
1, если
self.downcaseбольшеother_string.downcase. -
nil, если их невозможно сравнить.
Примеры:
'foo'.casecmp('goo') # => -1
'goo'.casecmp('foo') # => 1
'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, если они не равны, и nil, если их невозможно сравнить.
Примеры:
'foo'.casecmp?('goo') # => false
'goo'.casecmp?('foo') # => false
'foo'.casecmp?('food') # => false
'food'.casecmp?('foo') # => false
'FOO'.casecmp?('foo') # => true
'foo'.casecmp?('FOO') # => true
'foo'.casecmp?(1) # => nil
Связанные методы: см. Сравнение.
static VALUE
rb_str_center(int argc, VALUE *argv, VALUE str)
{
return rb_str_justify(argc, argv, str, 'c');
} Возвращает копию self, выровненную по центру.
Если целочисленный аргумент size больше размера self (в символах), возвращает новую строку длиной size, являющуюся копией self, выровненной по центру и дополненной с одной или обеих сторон строкой pad_string:
'hello'.center(6) # => "hello " # Padded on one end. 'hello'.center(10) # => " hello " # Padded on both ends. 'hello'.center(20, '-|') # => "-|-|-|-hello-|-|-|-|" # Some padding repeated. 'hello'.center(10, 'abcdefg') # => "abhelloabc" # Some padding not used. ' hello '.center(13) # => " hello " 'Привет'.center(10) # => " Привет " 'こんにちは'.center(10) # => " こんにちは " # Multi-byte characters.
Если size меньше или равен размеру self, возвращает копию self без дополнения:
'hello'.center(5) # => "hello" 'hello'.center(-10) # => "hello"
Связанные методы: см. Преобразование в новую строку.
static VALUE
rb_str_chars(VALUE str)
{
VALUE ary = WANTARRAY("chars", rb_str_strlen(str));
return rb_str_enumerate_chars(str, ary);
} Возвращает массив символов из self:
'hello'.chars # => ["h", "e", "l", "l", "o"] 'Привет'.chars # => ["П", "р", "и", "в", "е", "т"] 'こんにちは'.chars # => ["こ", "ん", "に", "ち", "は"] ''.chars # => []
Связанные методы: см. Преобразование в объект, не являющийся строкой.
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));
} Возвращает новую строку, скопированную из self, из которой могут быть удалены конечные символы:
Если line_sep равно "\n", удаляет один или два последних символа, если это "\r", "\n" или "\r\n" (но не "\n\r"):
$/ # => "\n" "abc\r".chomp # => "abc" "abc\n".chomp # => "abc" "abc\r\n".chomp # => "abc" "abc\n\r".chomp # => "abc\n" "тест\r\n".chomp # => "тест" "こんにちは\r\n".chomp # => "こんにちは"
Если line_sep равно '' (пустой строке), удаляет несколько повторяющихся конечных символов "\n" или "\r\n" (но не "\r" или "\n\r"):
"abc\n\n\n".chomp('') # => "abc"
"abc\r\n\r\n\r\n".chomp('') # => "abc"
"abc\n\n\r\n\r\n\n\n".chomp('') # => "abc"
"abc\n\r\n\r\n\r".chomp('') # => "abc\n\r\n\r\n\r"
"abc\r\r\r".chomp('') # => "abc\r\r\r"
Если line_sep не равно ни "\n", ни '', удаляет один конечный разделитель строки, если он есть:
'abcd'.chomp('cd') # => "ab"
'abcdcd'.chomp('cd') # => "abcd"
'abcd'.chomp('xx') # => "abcd"
Связанные методы: см. Преобразование в новую строку.
static VALUE
rb_str_chomp_bang(int argc, VALUE *argv, VALUE str)
{
VALUE rs;
str_modifiable(str);
if (RSTRING_LEN(str) == 0 && argc < 2) return Qnil;
rs = chomp_rs(argc, argv);
if (NIL_P(rs)) return Qnil;
return rb_str_chomp_string(str, rs);
} Как String#chomp, но:
-
Удаляет конечные символы из
self(а не из копииself). -
Возвращает
self, если какие-либо символы были удалены, иnilв противном случае.
Связанные методы: см. Изменение.
static VALUE
rb_str_chop(VALUE str)
{
return rb_str_subseq(str, 0, chopped_length(str));
} Возвращает новую строку, скопированную из self, из которой могут быть удалены конечные символы.
Удаляет "\r\n", если это два последних символа.
"abc\r\n".chop # => "abc" "тест\r\n".chop # => "тест" "こんにちは\r\n".chop # => "こんにちは"
В противном случае удаляет последний символ, если он есть.
'abcd'.chop # => "abc" 'тест'.chop # => "тес" 'こんにちは'.chop # => "こんにち" ''.chop # => ""
Если нужно удалить только разделитель новой строки в конце строки, лучше использовать String#chomp.
Связанные методы: см. Преобразование в новую строку.
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;
} Как String#chop, но:
-
Удаляет конечные символы из
self(а не из копииself). -
Возвращает
self, если какие-либо символы были удалены, иnilв противном случае.
Связанные методы: см. Изменение.
static VALUE
rb_str_chr(VALUE str)
{
return rb_str_substr(str, 0, 1);
} Возвращает строку, содержащую первый символ из self:
'hello'.chr # => "h" 'тест'.chr # => "т" 'こんにちは'.chr # => "こ" ''.chr # => ""
Связанные методы: см. Преобразование в новую строку.
static VALUE
rb_str_clear(VALUE str)
{
str_discard(str);
STR_SET_EMBED(str);
STR_SET_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;
} static VALUE
rb_str_codepoints(VALUE str)
{
VALUE ary = WANTARRAY("codepoints", rb_str_strlen(str));
return rb_str_enumerate_codepoints(str, ary);
} Возвращает массив кодовых точек из self; каждая кодовая точка — целочисленное значение символа:
'hello'.codepoints # => [104, 101, 108, 108, 111] 'тест'.codepoints # => [1090, 1077, 1089, 1090] 'こんにちは'.codepoints # => [12371, 12435, 12395, 12385, 12399] ''.codepoints # => []
Связанные методы: см. Преобразование в объект, не являющийся строкой.
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;
} Добавляет каждый объект из objects к self; возвращает self:
'foo'.concat('bar', 'baz') # => "foobarbaz"
Для каждого заданного объекта object, являющегося целым числом, его значение считается кодовой точкой и перед добавлением преобразуется в символ:
'foo'.concat(32, 'bar', 32, 'baz') # => "foo bar baz" # Embeds spaces. 'те'.concat(1089, 1090) # => "тест" 'こん'.concat(12395, 12385, 12399) # => "こんにちは"
Связанные методы: см. Преобразование в новую строку.
static VALUE
rb_str_count(int argc, VALUE *argv, VALUE str)
{
char table[TR_TABLE_SIZE];
rb_encoding *enc = 0;
VALUE del = 0, nodel = 0, tstr;
char *s, *send;
int i;
int ascompat;
size_t n = 0;
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
tstr = argv[0];
StringValue(tstr);
enc = rb_enc_check(str, tstr);
if (argc == 1) {
const char *ptstr;
if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
(ptstr = RSTRING_PTR(tstr),
ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (const unsigned char *)ptstr, (const unsigned char *)ptstr+1)) &&
!is_broken_string(str)) {
int clen;
unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);
s = RSTRING_PTR(str);
if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
send = RSTRING_END(str);
while (s < send) {
if (*(unsigned char*)s++ == c) n++;
}
return SIZET2NUM(n);
}
}
tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
for (i=1; i<argc; i++) {
tstr = argv[i];
StringValue(tstr);
enc = rb_enc_check(str, tstr);
tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
}
s = RSTRING_PTR(str);
if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
send = RSTRING_END(str);
ascompat = rb_enc_asciicompat(enc);
while (s < send) {
unsigned int c;
if (ascompat && (c = *(unsigned char*)s) < 0x80) {
if (table[c]) {
n++;
}
s++;
}
else {
int clen;
c = rb_enc_codepoint_len(s, send, &clen, enc);
if (tr_find(c, table, del, nodel)) {
n++;
}
s += clen;
}
}
return SIZET2NUM(n);
} Возвращает общее количество символов в self, соответствующих заданным селекторам.
Для одного односимвольного селектора возвращает количество вхождений этого символа:
s = 'abracadabra'
s.count('a') # => 5
s.count('b') # => 2
s.count('x') # => 0
s.count('') # => 0
s = 'тест'
s.count('т') # => 2
s.count('е') # => 1
s = 'よろしくお願いします'
s.count('よ') # => 1
s.count('し') # => 2
Для одного многосимвольного селектора возвращает количество вхождений всех указанных символов:
s = 'abracadabra'
s.count('ab') # => 7
s.count('abc') # => 8
s.count('abcd') # => 9
s.count('abcdr') # => 11
s.count('abcdrx') # => 11
Порядок и повторения не имеют значения:
s.count('ba') == s.count('ab') # => true
s.count('baab') == s.count('ab') # => true
Для нескольких селекторов формирует единый селектор, представляющий собой пересечение символов во всех селекторах, и возвращает количество вхождений символов, соответствующих этому селектору:
s = 'abcdefg'
s.count('abcde', 'dcbfg') == s.count('bcd') # => true
s.count('abc', 'def') == s.count('') # => true
В селекторе символов три символа обрабатываются особым образом:
-
Карет (
'^') служит оператором отрицания для непосредственно следующих за ним символов:s = 'abracadabra' s.count('^bc') # => 8 # Count of all except 'b' and 'c'. -
Дефис (
'-') между двумя другими символами задаёт диапазон символов:s = 'abracadabra' s.count('a-c') # => 8 # Count of all 'a', 'b', and 'c'. -
Обратная косая черта (
'\') экранирует карет, дефис или другую обратную косую черту:s = 'abracadabra' s.count('\^bc') # => 3 # Count of '^', 'b', and 'c'. s.count('a\-c') # => 6 # Count of 'a', '-', and 'c'. 'foo\bar\baz'.count('\\') # => 2 # Count of '\'.
Эти варианты использования можно комбинировать:
s = 'abracadabra'
s.count('a-cq-t') # => 10 # Multiple ranges.
s.count('ac-d') # => 7 # Range mixed with plain characters.
s.count('^a-c') # => 3 # Range mixed with negation.
Для нескольких селекторов можно использовать все варианты, включая отрицания, диапазоны и экранирование.
s = 'abracadabra'
s.count('^abc', '^def') == s.count('^abcdef') # => true
s.count('a-e', 'c-g') == s.count('cde') # => true
s.count('^abc', 'c-g') == s.count('defg') # => true
См. также: Запросы.
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
char *tmp_buf;
extern char *crypt(const char *, const char *);
# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
#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);
s = StringValueCStr(str);
saltp = RSTRING_PTR(salt);
if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
rb_raise(rb_eArgError, "salt too short (need >=2 bytes)");
}
#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
rb_nativethread_lock_lock(&crypt_mutex.lock);
res = crypt(s, saltp);
#endif
if (!res) {
int err = errno;
CRYPT_END();
rb_syserr_fail(err, "crypt");
}
#ifdef HAVE_CRYPT_R
result = rb_str_new_cstr(res);
CRYPT_END();
#else
// We need to copy this buffer because it's static and we need to unlock the mutex
// before allocating a new object (the string to be returned). If we allocate while
// holding the lock, we could run GC which fires the VM barrier and causes a deadlock
// if other ractors are waiting on this lock.
size_t res_size = strlen(res)+1;
tmp_buf = ALLOCA_N(char, res_size); // should be small enough to alloca
memcpy(tmp_buf, res, res_size);
res = tmp_buf;
CRYPT_END();
result = rb_str_new_cstr(res);
#endif
return result;
} Возвращает строку, полученную вызовом функции стандартной библиотеки crypt(3) с аргументами str и salt_str именно в таком порядке. Пожалуйста, больше не используйте этот метод. Он устарел и предоставляется только для обратной совместимости со скриптами Ruby прошлых лет. Его не следует применять в современных программах по нескольким причинам:
-
Поведение функции C
crypt(3)зависит от операционной системы, в которой она выполняется. Сгенерированная строка не переносима между системами. -
В некоторых операционных системах, например Mac OS,
crypt(3)никогда не завершается ошибкой (то есть может незаметно привести к неожиданным результатам). -
В некоторых операционных системах, например Mac OS,
crypt(3)не является потокобезопасным. -
Так называемый «традиционный» способ использования
crypt(3)очень и очень слаб. Согласно man-странице, традиционный выводcrypt(3)в Linux имеет всего 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/ . Другой пример: модуль$3$считается полностью небезопасным: см. man-страницу FreeBSD. -
В некоторых операционных системах, например Mac OS, модульный режим отсутствует. Однако, как сказано выше,
crypt(3)в Mac OS никогда не завершается ошибкой. Это означает, что даже при формировании корректной строки соли всё равно создаётся традиционный хеш DES, и вы никак не сможете об этом узнать."foo".crypt("$5$rounds=1000$salt$") # => "$5fNPQMxC5j6."
Если по какой-либо причине вы не можете перейти на другие современные алгоритмы хеширования паролей, установите гем string-crypt и require 'string/crypt', чтобы продолжить его использовать.
Возвращает замороженную строку, равную self.
Возвращённая строка является self тогда и только тогда, когда выполняются все следующие условия:
-
selfуже заморожена. -
selfявляется экземпляром String (а не экземпляром подкласса String) -
Для
selfне заданы переменные экземпляра.
В противном случае возвращённая строка является замороженной копией self.
Если возможно, возвращение self позволяет избежать дублирования self; см. дедупликация данных.
Это также может помочь избежать дублирования других уже существующих строк:
s0 = 'foo' s1 = 'foo' s0.object_id == s1.object_id # => false (-s0).object_id == (-s1).object_id # => true
Обратите внимание, что метод -@ удобен для определения константы:
FileName = -'config/database.yml'
А его псевдоним dedup лучше подходит для цепочек вызовов:
'foo'.dedup.gsub!('o')
См. также: Замораживание/размораживание.
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;
} Возвращает новую строку, являющуюся копией self, из которой удалены определённые символы; удаляются все вхождения символов, указанных в заданной строке selectors.
Для одного односимвольного селектора удаляются все вхождения этого символа:
s = 'abracadabra'
s.delete('a') # => "brcdbr"
s.delete('b') # => "aracadara"
s.delete('x') # => "abracadabra"
s.delete('') # => "abracadabra"
s = 'тест'
s.delete('т') # => "ес"
s.delete('е') # => "тст"
s = 'よろしくお願いします'
s.delete('よ') # => "ろしくお願いします"
s.delete('し') # => "よろくお願います"
Для одного многосимвольного селектора удаляются все вхождения указанных символов:
s = 'abracadabra'
s.delete('ab') # => "rcdr"
s.delete('abc') # => "rdr"
s.delete('abcd') # => "rr"
s.delete('abcdr') # => ""
s.delete('abcdrx') # => ""
Порядок и повторения не имеют значения:
s.delete('ba') == s.delete('ab') # => true
s.delete('baab') == s.delete('ab') # => true
Для нескольких селекторов формируется единый селектор, представляющий собой пересечение символов во всех селекторах, и удаляются все вхождения символов, указанных этим селектором:
s = 'abcdefg'
s.delete('abcde', 'dcbfg') == s.delete('bcd') # => true
s.delete('abc', 'def') == s.delete('') # => true
В селекторе символов три символа обрабатываются особым образом:
-
Карет (
'^') служит оператором отрицания для непосредственно следующих за ним символов:s = 'abracadabra' s.delete('^bc') # => "bcb" # Deletes all except 'b' and 'c'. -
Дефис (
'-') между двумя другими символами задаёт диапазон символов:s = 'abracadabra' s.delete('a-c') # => "rdr" # Deletes all 'a', 'b', and 'c'. -
Обратная косая черта (
'\') экранирует карет, дефис или другую обратную косую черту:s = 'abracadabra' s.delete('\^bc') # => "araadara" # Deletes all '^', 'b', and 'c'. s.delete('a\-c') # => "brdbr" # Deletes all 'a', '-', and 'c'. 'foo\bar\baz'.delete('\\') # => "foobarbaz" # Deletes all '\'.
Эти варианты использования можно комбинировать:
s = 'abracadabra'
s.delete('a-cq-t') # => "d" # Multiple ranges.
s.delete('ac-d') # => "brbr" # Range mixed with plain characters.
s.delete('^a-c') # => "abacaaba" # Range mixed with negation.
Для нескольких селекторов можно использовать все варианты, включая отрицания, диапазоны и экранирование.
s = 'abracadabra'
s.delete('^abc', '^def') == s.delete('^abcdef') # => true
s.delete('a-e', 'c-g') == s.delete('cde') # => true
s.delete('^abc', 'c-g') == s.delete('defg') # => true
См. также: Преобразование в новую строку.
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;
} Как String#delete, но изменяет self на месте; возвращает self, если были удалены какие-либо символы, и nil в противном случае.
См. также: Изменение.
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);
} Возвращает копию self с удалённой начальной подстрокой prefix:
'oof'.delete_prefix('o') # => "of"
'oof'.delete_prefix('oo') # => "f"
'oof'.delete_prefix('oof') # => ""
'oof'.delete_prefix('x') # => "oof"
'тест'.delete_prefix('те') # => "ст"
'こんにちは'.delete_prefix('こん') # => "にちは"
См. также: Преобразование в новую строку.
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);
} Как String#delete_prefix, но self изменяется на месте; возвращает self, если префикс удалён, и 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);
} Возвращает копию self с удалённой конечной подстрокой suffix:
'foo'.delete_suffix('o') # => "fo"
'foo'.delete_suffix('oo') # => "f"
'foo'.delete_suffix('foo') # => ""
'foo'.delete_suffix('f') # => "foo"
'foo'.delete_suffix('x') # => "foo"
'тест'.delete_suffix('ст') # => "те"
'こんにちは'.delete_suffix('ちは') # => "こんに"
См. также: Преобразование в новую строку.
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;
} Как String#delete_suffix, но self изменяется на месте; возвращает self, если суффикс удалён, и 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_direct(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;
} Возвращает новую строку, содержащую символы self в нижнем регистре:
'HELLO'.downcase # => "hello" 'STRAẞE'.downcase # => "straße" 'ПРИВЕТ'.downcase # => "привет" 'RubyGems.org'.downcase # => "rubygems.org"
Некоторые символы (и некоторые наборы символов) не имеют вариантов в верхнем и нижнем регистре; см. Изменение регистра:
s = '1, 2, 3, ...' s.downcase == s # => true s = 'こんにちは' s.downcase == s # => true
Преобразование регистра зависит от заданного mapping, которым может быть :ascii, :fold или :turkic; см. Преобразования регистра.
См. также: Преобразование в новую строку.
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;
} Как String#downcase, но:
-
Изменяет регистр символов в
self(а не в копииself). -
Возвращает
self, если были внесены изменения, иnilв противном случае.
См. также: Изменение.
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;
} Для обычной строки этот метод, +String#dump+, возвращает версию self, пригодную для печати и состоящую только из символов ASCII, заключённую в двойные кавычки.
Для дампированной строки метод String#undump является обратным к +String#dump+; он возвращает «восстановленную» версию self, отменяя все изменения, внесённые при создании дампа.
В простейшем случае дампированная строка содержит исходную строку, заключённую в двойные кавычки; этот пример выполнен в irb (интерактивной среде Ruby), где для вывода результатов используется метод ‘inspect`:
s = 'hello' # => "hello" s.dump # => "\"hello\"" s.dump.undump # => "hello"
Обратите внимание, что во второй строке выше:
-
Внешние двойные кавычки добавлены
inspectи не являются частью выводаdump. -
Внутренние двойные кавычки являются частью вывода
dumpи экранируютсяinspect, поскольку находятся внутри внешних двойных кавычек.
Чтобы избежать путаницы, воспользуемся вспомогательным методом, который убирает внешние двойные кавычки:
def dump(s) print "String: ", s, "\n" print "Dumped: ", s.dump, "\n" print "Undumped: ", s.dump.undump, "\n" end
Для строки 'hello' мы увидим:
String: hello Dumped: "hello" Undumped: hello
В дампе некоторые специальные символы экранируются:
String: " Dumped: "\"" Undumped: " String: \ Dumped: "\\" Undumped: \
В дампе непечатаемые символы заменяются печатаемыми; к непечатаемым символам относятся пробельные символы (кроме самого пробела). Здесь мы видим порядковые номера этих символов и поясняющий текст:
h = {
7 => 'Alert (BEL)',
8 => 'Backspace (BS)',
9 => 'Horizontal tab (HT)',
10 => 'Linefeed (LF)',
11 => 'Vertical tab (VT)',
12 => 'Formfeed (FF)',
13 => 'Carriage return (CR)'
}
В этом примере дампированный вывод печатается методом inspect, поэтому содержит как внешние двойные кавычки, так и экранированные внутренние двойные кавычки:
s = ''
h.keys.each {|i| s << i } # => [7, 8, 9, 10, 11, 12, 13]
s # => "\a\b\t\n\v\f\r"
s.dump # => "\"\\a\\b\\t\\n\\v\\f\\r\""
Если self закодирована в UTF-8 и содержит символы Unicode, каждый символ Unicode преобразуется в escape-последовательность Unicode:
String: тест Dumped: "\u0442\u0435\u0441\u0442" Undumped: тест String: こんにちは Dumped: "\u3053\u3093\u306B\u3061\u306F" Undumped: こんにちは
Если кодировка self несовместима с ASCII (то есть если self.encoding.ascii_compatible? возвращает false), каждый совместимый с ASCII байт выводится как символ ASCII, а все остальные байты — в шестнадцатеричном формате; также добавляется .dup.force_encoding(\"encoding\"), где <encoding> — это self.encoding.name:
String: hello
Dumped: "\xFE\xFF\x00h\x00e\x00l\x00l\x00o".dup.force_encoding("UTF-16")
Undumped: hello
String: тест
Dumped: "\xFE\xFF\x04B\x045\x04A\x04B".dup.force_encoding("UTF-16")
Undumped: тест
String: こんにちは
Dumped: "\xFE\xFF0S0\x930k0a0o".dup.force_encoding("UTF-16")
Undumped: こんにちは 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);
} Если передан блок, вызывает его для каждого следующего байта из self; возвращает self:
a = []
'hello'.each_byte {|byte| a.push(byte) } # Five 1-byte characters.
a # => [104, 101, 108, 108, 111]
a = []
'тест'.each_byte {|byte| a.push(byte) } # Four 2-byte characters.
a # => [209, 130, 208, 181, 209, 129, 209, 130]
a = []
'こんにちは'.each_byte {|byte| a.push(byte) } # Five 3-byte characters.
a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
Если блок не передан, возвращает перечислитель.
См. также: Итерация.
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);
} Если передан блок, вызывает его для каждого следующего символа из self; возвращает self:
a = [] 'hello'.each_char do |char| a.push(char) end a # => ["h", "e", "l", "l", "o"] a = [] 'тест'.each_char do |char| a.push(char) end a # => ["т", "е", "с", "т"] a = [] 'こんにちは'.each_char do |char| a.push(char) end a # => ["こ", "ん", "に", "ち", "は"]
Если блок не передан, возвращает перечислитель.
См. также: Итерация.
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);
} Если передан блок, вызывает его для каждой следующей кодовой точки из self; каждая кодовая точка — это целочисленное значение символа; возвращает self:
a = [] 'hello'.each_codepoint do |codepoint| a.push(codepoint) end a # => [104, 101, 108, 108, 111] a = [] 'тест'.each_codepoint do |codepoint| a.push(codepoint) end a # => [1090, 1077, 1089, 1090] a = [] 'こんにちは'.each_codepoint do |codepoint| a.push(codepoint) end a # => [12371, 12435, 12395, 12385, 12399]
Если блок не передан, возвращает перечислитель.
См. также: Итерация.
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);
} Если передан блок, вызывает его для каждого следующего кластера графем из self (см. границы кластеров графем Unicode); возвращает self:
a = [] 'hello'.each_grapheme_cluster do |grapheme_cluster| a.push(grapheme_cluster) end a # => ["h", "e", "l", "l", "o"] a = [] 'тест'.each_grapheme_cluster do |grapheme_cluster| a.push(grapheme_cluster) end a # => ["т", "е", "с", "т"] a = [] 'こんにちは'.each_grapheme_cluster do |grapheme_cluster| a.push(grapheme_cluster) end a # => ["こ", "ん", "に", "ち", "は"]
Если блок не передан, возвращает перечислитель.
См. также: Итерация.
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);
} Если передан блок, формирует подстроки (строки), полученные при разделении self в каждом месте вхождения заданного record_separator; передаёт каждую строку блоку; возвращает self.
С разделителем record_separator по умолчанию:
$/ # => "\n"
s = <<~EOT
This is the first line.
This is line two.
This is line four.
This is line five.
EOT
s.each_line {|line| p line }
Вывод:
"This is the first line.\n" "This is line two.\n" "\n" "This is line four.\n" "This is line five.\n"
С другим значением record_separator:
record_separator = ' is '
s.each_line(record_separator) {|line| p line }
Вывод:
"This is " "the first line.\nThis is " "line two.\n\nThis is " "line four.\nThis is " "line five.\n"
Если chomp равен true, удаляет конечный record_separator из каждой строки:
s.each_line(chomp: true) {|line| p line }
Вывод:
"This is the first line." "This is line two." "" "This is line four." "This is line five."
Если в качестве record_separator указана пустая строка, формирует и передаёт «абзацы», разделяя текст при каждом вхождении двух или более символов новой строки:
record_separator = ''
s.each_line(record_separator) {|line| p line }
Вывод:
"This is the first line.\nThis is line two.\n\n" "This is line four.\nThis is line five.\n"
Если блок не передан, возвращает перечислитель.
См. также: Итерация.
static VALUE
rb_str_empty(VALUE str)
{
return RBOOL(RSTRING_LEN(str) == 0);
} Возвращает, равна ли длина self нулю:
'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);
} Возвращает копию self, преобразованную в соответствии с dst_encoding; см. Кодировки.
По умолчанию вызывает исключение, если self содержит недопустимый байт или символ, не определённый в dst_encoding; это поведение можно изменить с помощью параметров кодирования; см. ниже.
Без аргументов:
-
Используется та же кодировка, если
Encoding.default_internalравенnil(значение по умолчанию):Encoding.default_internal # => nil s = "Ruby\x99".force_encoding('Windows-1252') s.encoding # => #<Encoding:Windows-1252> s.bytes # => [82, 117, 98, 121, 153] t = s.encode # => "Ruby\x99" t.encoding # => #<Encoding:Windows-1252> t.bytes # => [82, 117, 98, 121, 226, 132, 162] -
В противном случае используется кодировка
Encoding.default_internal:Encoding.default_internal = 'UTF-8' t = s.encode # => "Ruby™" t.encoding # => #<Encoding:UTF-8>
Если указан только аргумент dst_encoding, используется эта кодировка:
s = "Ruby\x99".force_encoding('Windows-1252')
s.encoding # => #<Encoding:Windows-1252>
t = s.encode('UTF-8') # => "Ruby™"
t.encoding # => #<Encoding:UTF-8>
Если указаны аргументы dst_encoding и src_encoding, self интерпретируется с использованием src_encoding, а новая строка кодируется с использованием dst_encoding:
s = "Ruby\x99"
t = s.encode('UTF-8', 'Windows-1252') # => "Ruby™"
t.encoding # => #<Encoding:UTF-8>
Необязательные именованные аргументы enc_opts задают параметры кодирования; см. Параметры кодирования.
Обратите внимание: если не указан параметр invalid: :replace, преобразование из кодировки enc в ту же кодировку enc (независимо от того, задан ли enc явно или неявно) не выполняется; строка просто копируется без изменений, и исключения не вызываются, даже если она содержит недопустимые байты.
См. также: Преобразование в новую строку.
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);
} 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);
} static VALUE
rb_str_end_with(int argc, VALUE *argv, VALUE str)
{
int i;
for (i=0; i<argc; i++) {
VALUE tmp = argv[i];
const char *p, *s, *e;
long slen, tlen;
rb_encoding *enc;
StringValue(tmp);
enc = rb_enc_check(str, tmp);
if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
if ((slen = RSTRING_LEN(str)) < tlen) continue;
p = RSTRING_PTR(str);
e = p + slen;
s = e - tlen;
if (!at_char_boundary(p, s, e, enc))
continue;
if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
return Qtrue;
}
return Qfalse;
} Возвращает, оканчивается ли self любой из заданных strings:
'foo'.end_with?('oo') # => true
'foo'.end_with?('bar', 'oo') # => true
'foo'.end_with?('bar', 'baz') # => false
'foo'.end_with?('') # => true
'тест'.end_with?('т') # => true
'こんにちは'.end_with?('は') # => true
См. также: Проверка.
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);
} Возвращает, имеют ли self и object одинаковую длину и содержимое:
s = 'foo'
s.eql?('foo') # => true
s.eql?('food') # => false
s.eql?('FOO') # => false
Возвращает false, если кодировки двух строк несовместимы:
s0 = "äöü" # => "äöü" s1 = s0.encode(Encoding::ISO_8859_1) # => "\xE4\xF6\xFC" s0.encoding # => #<Encoding:UTF-8> s1.encoding # => #<Encoding:ISO-8859-1> s0.eql?(s1) # => false
См. Кодировки.
См. также: Проверка.
static VALUE
rb_str_force_encoding(VALUE str, VALUE enc)
{
str_modifiable(str);
rb_encoding *encoding = rb_to_encoding(enc);
int idx = rb_enc_to_index(encoding);
// If the encoding is unchanged, we do nothing.
if (ENCODING_GET(str) == idx) {
return str;
}
rb_enc_associate_index(str, idx);
// If the coderange was 7bit and the new encoding is ASCII-compatible
// we can keep the coderange.
if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT && encoding && rb_enc_asciicompat(encoding)) {
return str;
}
ENC_CODERANGE_CLEAR(str);
return str;
} Изменяет кодировку self на указанную encoding, которой может быть название кодировки в виде строки или объект Encoding; базовые байты не изменяются; возвращает self:
s = 'łał'
s.bytes # => [197, 130, 97, 197, 130]
s.encoding # => #<Encoding:UTF-8>
s.force_encoding('ascii') # => "\xC5\x82a\xC5\x82"
s.encoding # => #<Encoding:US-ASCII>
s.valid_encoding? # => true
s.bytes # => [197, 130, 97, 197, 130]
Изменение выполняется, даже если указанная encoding недопустима для self (как и в приведённом выше примере):
s.valid_encoding? # => false
См. Кодировки.
Связанный раздел: Изменение.
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, отсчитываемому с нуля, в виде целого числа:
s = 'foo' s.getbyte(0) # => 102 s.getbyte(1) # => 111 s.getbyte(2) # => 111
Если index отрицателен, отсчёт ведётся от конца:
s.getbyte(-3) # => 102
Возвращает nil, если index выходит за допустимые границы:
s.getbyte(3) # => nil s.getbyte(-4) # => nil
Другие примеры:
s = 'тест' s.bytes # => [209, 130, 208, 181, 209, 129, 209, 130] s.getbyte(2) # => 208 s = 'こんにちは' s.bytes # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175] s.getbyte(2) # => 147
Связанный раздел: Преобразование в нестроковое значение.
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);
} Возвращает массив графемных кластеров в self (см. Границы графемных кластеров Unicode):
s = "ä-pqr-b̈-xyz-c̈" s.size # => 16 s.bytesize # => 19 s.grapheme_clusters.size # => 13 s.grapheme_clusters # => ["ä", "-", "p", "q", "r", "-", "b̈", "-", "x", "y", "z", "-", "c̈"]
Подробности:
s = "ä"
s.grapheme_clusters # => ["ä"] # One grapheme cluster.
s.bytes # => [97, 204, 136] # Three bytes.
s.chars # => ["a", "̈"] # Two characters.
s.chars.map {|char| char.ord } # => [97, 776] # Their values.
Связанный раздел: Преобразование в нестроковое значение.
static VALUE
rb_str_gsub(int argc, VALUE *argv, VALUE str)
{
return str_gsub(argc, argv, str, 0);
} Возвращает копию self, в которой заменены ноль или более подстрок.
Аргумент pattern может быть строкой или Regexp; аргумент replacement может быть строкой или Hash. Возможность использовать аргументы разных типов делает этот метод очень универсальным.
Ниже приведены несколько простых примеров; дополнительные примеры см. в разделе Методы подстановки.
Если переданы аргументы pattern и строка replacement, каждая совпавшая подстрока заменяется указанной строкой replacement:
s = 'abracadabra'
s.gsub('ab', 'AB') # => "ABracadABra"
s.gsub(/[a-c]/, 'X') # => "XXrXXXdXXrX"
Если переданы аргументы pattern и хеш replacement, каждая совпавшая подстрока заменяется значением из указанного хеша replacement или удаляется:
h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
s.gsub(/[a-c]/, h) # => "ABrACAdABrA" # 'a', 'b', 'c' replaced.
s.gsub(/[a-d]/, h) # => "ABrACAABrA" # 'd' removed.
Если передан аргумент pattern и блок, блок вызывается для каждой совпавшей подстроки; эта подстрока заменяется возвращаемым блоком значением:
s.gsub(/[a-d]/) {|substring| substring.upcase }
# => "ABrACADABrA"
Если передан аргумент pattern без блока, возвращается новый Enumerator.
Связанный раздел: Преобразование в новую строку.
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, но:
-
Выполняет подстановки непосредственно в
self(а не в копииself). -
Возвращает
self, если были удалены какие-либо символы, иnilв противном случае.
Связанный раздел: Изменение.
static VALUE
rb_str_hash_m(VALUE str)
{
st_index_t hval = rb_str_hash(str);
return ST2FIX(hval);
} Возвращает целочисленное хеш-значение для self.
Два объекта String с одинаковым содержимым и совместимыми кодировками также имеют одинаковые хеш-значения; см. Object#hash и Кодировки:
s = 'foo' h = s.hash # => -569050784 h == 'foo'.hash # => true h == 'food'.hash # => false h == 'FOO'.hash # => false s0 = "äöü" s1 = s0.encode(Encoding::ISO_8859_1) s0.encoding # => #<Encoding:UTF-8> s1.encoding # => #<Encoding:ISO-8859-1> s0.hash == s1.hash # => false
Связанный раздел: Запросы.
static VALUE
rb_str_hex(VALUE str)
{
return rb_str_to_inum(str, 16, FALSE);
} Интерпретирует начальную подстроку self как шестнадцатеричное число, возможно со знаком; возвращает его значение в виде целого числа.
Начальная подстрока интерпретируется как шестнадцатеричное число, если она начинается с:
-
Одного или нескольких символов, представляющих шестнадцатеричные цифры (каждая из диапазонов
'0'..'9','a'..'f'или'A'..'F'); интерпретация строки заканчивается на первом символе, который не является шестнадцатеричной цифрой:'f'.hex # => 15 '11'.hex # => 17 'FFF'.hex # => 4095 'fffg'.hex # => 4095 'foo'.hex # => 15 # 'f' hexadecimal, 'oo' not. 'bar'.hex # => 186 # 'ba' hexadecimal, 'r' not. 'deadbeef'.hex # => 3735928559
-
'0x'или'0X', за которыми следуют одна или несколько шестнадцатеричных цифр:'0xfff'.hex # => 4095 '0xfffg'.hex # => 4095
Перед любой из указанных выше последовательностей может стоять '-', который меняет знак интерпретируемого значения на противоположный:
'-fff'.hex # => -4095 '-0xFFF'.hex # => -4095
Для любой подстроки, не описанной выше, возвращает ноль:
'xxx'.hex # => 0 ''.hex # => 0
Обратите внимание: в отличие от oct, этот метод интерпретирует только шестнадцатеричную запись, но не двоичную, восьмеричную или десятичную:
'0b111'.hex # => 45329 '0o777'.hex # => 0 '0d999'.hex # => 55705
Связанный раздел: см. Преобразование в нестроковое значение.
VALUE
rb_str_include(VALUE str, VALUE arg)
{
long i;
StringValue(arg);
i = rb_str_index(str, arg, 0);
return RBOOL(i != -1);
} Возвращает значение, указывающее, содержит ли self строку other_string:
s = 'bar'
s.include?('ba') # => true
s.include?('ar') # => true
s.include?('bar') # => true
s.include?('a') # => true
s.include?('') # => true
s.include?('foo') # => false
Связанный раздел: Запросы.
static VALUE
rb_str_index_m(int argc, VALUE *argv, VALUE str)
{
VALUE sub;
VALUE initpos;
rb_encoding *enc = STR_ENC_GET(str);
long pos;
if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
long slen = str_strlen(str, enc); /* str's enc */
pos = NUM2LONG(initpos);
if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
if (RB_TYPE_P(sub, T_REGEXP)) {
rb_backref_set(Qnil);
}
return Qnil;
}
}
else {
pos = 0;
}
if (RB_TYPE_P(sub, T_REGEXP)) {
pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
enc, single_byte_optimizable(str));
if (rb_reg_search(sub, str, pos, 0) >= 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_index(str, sub, pos);
if (pos >= 0) {
pos = rb_str_sublen(str, pos);
return LONG2NUM(pos);
}
}
return Qnil;
} Возвращает целочисленную позицию первой подстроки, соответствующей заданному аргументу pattern, или nil, если совпадений нет.
Если pattern — строка, возвращает индекс первой совпавшей подстроки в self:
'foo'.index('f') # => 0
'foo'.index('o') # => 1
'foo'.index('oo') # => 1
'foo'.index('ooo') # => nil
'тест'.index('с') # => 2 # Characters, not bytes.
'こんにちは'.index('ち') # => 3
Если pattern — это Regexp, возвращает индекс первого совпадения в self:
'foo'.index(/o./) # => 1 'foo'.index(/.o/) # => 0
Если offset неотрицателен, поиск начинается с позиции offset; возвращаемый индекс отсчитывается от начала self:
'bar'.index('r', 0) # => 2
'bar'.index('r', 1) # => 2
'bar'.index('r', 2) # => 2
'bar'.index('r', 3) # => nil
'bar'.index(/[r-z]/, 0) # => 2
'тест'.index('с', 1) # => 2
'тест'.index('с', 2) # => 2
'тест'.index('с', 3) # => nil # Offset in characters, not bytes.
'こんにちは'.index('ち', 2) # => 3
При отрицательном целочисленном аргументе offset позиция поиска определяется отсчётом от конца self:
'foo'.index('o', -1) # => 2
'foo'.index('o', -2) # => 1
'foo'.index('o', -3) # => 1
'foo'.index('o', -4) # => nil
'foo'.index(/o./, -2) # => 1
'foo'.index(/.o/, -2) # => 1
Связанный раздел: Запросы.
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_update(str, pos, 0, str2);
return str;
} Вставляет указанную other_string в self; возвращает self.
Если указанная index неотрицательна, other_string вставляется по смещению index:
'foo'.insert(0, 'bar') # => "barfoo" 'foo'.insert(1, 'bar') # => "fbaroo" 'foo'.insert(3, 'bar') # => "foobar" 'тест'.insert(2, 'bar') # => "теbarст" # Characters, not bytes. 'こんにちは'.insert(2, 'bar') # => "こんbarにちは"
Если index отрицательна, отсчёт ведётся от конца self, а other_string вставляется после указанного смещения:
'foo'.insert(-2, 'bar') # => "fobaro"
Связанный раздел: Изменение.
VALUE
rb_str_inspect(VALUE str)
{
int encidx = ENCODING_GET(str);
rb_encoding *enc = rb_enc_from_index(encidx);
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;
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;
}
/* The special casing of 0x85 (NEXT_LINE) here is because
* Oniguruma historically treats it as printable, but it
* doesn't match the print POSIX bracket class or character
* property in regexps.
*
* See Ruby Bug #16842 for details:
* https://bugs.ruby-lang.org/issues/16842
*/
if ((enc == resenc && rb_enc_isprint(c, enc) && c != 0x85) ||
(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;
} Возвращает пригодное для печати представление self, заключённое в двойные кавычки.
Большинство печатных символов отображаются без изменений:
'abc'.inspect # => "\"abc\"" '012'.inspect # => "\"012\"" ''.inspect # => "\"\"" "\u000012".inspect # => "\"\\u000012\"" 'тест'.inspect # => "\"тест\"" 'こんにちは'.inspect # => "\"こんにちは\""
Однако печатные символы двойной кавычки ('"') и обратной косой черты ('\') экранируются:
'"'.inspect # => "\"\\\"\"" '\\'.inspect # => "\"\\\\\""
Непечатаемые символы — это символы ASCII со значениями в диапазоне 0..31, а также символ со значением 127.
Большинство таких символов отображаются следующим образом:
0.chr.inspect # => "\"\\x00\"" 1.chr.inspect # => "\"\\x01\"" 2.chr.inspect # => "\"\\x02\"" # ...
Однако некоторые из них имеют особое представление:
7.chr.inspect # => "\"\\a\"" # BEL 8.chr.inspect # => "\"\\b\"" # BS 9.chr.inspect # => "\"\\t\"" # TAB 10.chr.inspect # => "\"\\n\"" # LF 11.chr.inspect # => "\"\\v\"" # VT 12.chr.inspect # => "\"\\f\"" # FF 13.chr.inspect # => "\"\\r\"" # CR 27.chr.inspect # => "\"\\e\"" # ESC
Связанный раздел: Преобразование в нестроковое значение.
VALUE
rb_str_intern(VALUE str)
{
return sym_find_or_insert_dynamic_symbol(&ruby_global_symbols, str);
} Возвращает объект Symbol, созданный на основе self; если такого объекта ещё не было, он создаётся:
'foo'.intern # => :foo 'тест'.intern # => :тест 'こんにちは'.intern # => :こんにちは
Связанный раздел: Преобразование в нестроковое значение.
VALUE
rb_str_length(VALUE str)
{
return LONG2NUM(str_strlen(str, NULL));
} Возвращает количество символов (не байтов) в self:
'foo'.length # => 3 'тест'.length # => 4 'こんにちは'.length # => 5
Сравните с String#bytesize:
'foo'.bytesize # => 3 'тест'.bytesize # => 8 'こんにちは'.bytesize # => 15
Связанный раздел: Запросы.
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);
} Возвращает подстроки («строки») из self в соответствии с заданными аргументами:
s = <<~EOT This is the first line. This is line two. This is line four. This is line five. EOT
Со значениями аргументов по умолчанию:
$/ # => "\n" s.lines # => ["This is the first line.\n", "This is line two.\n", "\n", "This is line four.\n", "This is line five.\n"]
С другим record_separator:
record_separator = ' is ' s.lines(record_separator) # => ["This is ", "the first line.\nThis is ", "line two.\n\nThis is ", "line four.\nThis is ", "line five.\n"]
Если ключевой аргумент chomp задан как true, удаляет завершающий символ новой строки из каждой строки:
s.lines(chomp: true) # => ["This is the first line.", "This is line two.", "", "This is line four.", "This is line five."]
Связано: см. Преобразование в нестроковый объект.
static VALUE
rb_str_ljust(int argc, VALUE *argv, VALUE str)
{
return rb_str_justify(argc, argv, str, 'l');
} Возвращает копию self, выровненную по левому краю и, если необходимо, дополненную справа символами pad_string:
'hello'.ljust(10) # => "hello " ' hello'.ljust(10) # => " hello " 'hello'.ljust(10, 'ab') # => "helloababa" 'тест'.ljust(10) # => "тест " 'こんにちは'.ljust(10) # => "こんにちは "
Если width <= self.length, возвращает копию self:
'hello'.ljust(5) # => "hello" 'hello'.ljust(1) # => "hello" # Does not truncate to width.
Связано: см. Преобразование в новую строку.
static VALUE
rb_str_lstrip(int argc, VALUE *argv, VALUE str)
{
char *start;
long len, loffset;
RSTRING_GETMEM(str, start, len);
if (argc > 0) {
char table[TR_TABLE_SIZE];
VALUE del = 0, nodel = 0;
tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
loffset = lstrip_offset_table(str, start, start+len, STR_ENC_GET(str), table, del, nodel);
}
else {
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);
} Возвращает копию self без начальных пробельных символов; см. Пробельные символы в строках:
whitespace = "\x00\t\n\v\f\r " s = whitespace + 'abc' + whitespace # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r " s.lstrip # => "abc\u0000\t\n\v\f\r "
Если заданы selectors, удаляет символы из selectors в начале self:
s = "---abc+++"
s.lstrip("-") # => "abc+++"
selectors должны быть допустимыми селекторами символов (см. Селекторы символов) и могут использовать любую допустимую форму, включая отрицание, диапазоны и escape-последовательности:
"01234abc56789".lstrip("0-9") # "abc56789"
"01234abc56789".lstrip("0-9", "^4-6") # "4abc56789"
Связано: см. Преобразование в новую строку.
static VALUE
rb_str_lstrip_bang(int argc, VALUE *argv, 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);
if (argc > 0) {
char table[TR_TABLE_SIZE];
VALUE del = 0, nodel = 0;
tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
}
else {
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);
TERM_FILL(start+len, rb_enc_mbminlen(enc));
return str;
}
return Qnil;
} Как String#lstrip, за исключением того, что:
-
Удаление выполняется непосредственно в
self(а не в копииself). -
Возвращает
self, если были удалены какие-либо символы, и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 на основе self и заданных аргументов; обновляет глобальные переменные Regexp.
-
Вычисляет
regexp, преобразуяpattern(если это ещё неRegexp).regexp = Regexp.new(pattern)
-
Вычисляет
matchdata, которым будет либо объектMatchData, либоnil(см.Regexp#match):matchdata = regexp.match(self[offset..])
Если блок не задан, возвращает вычисленное matchdata или nil:
'foo'.match('f') # => #<MatchData "f">
'foo'.match('o') # => #<MatchData "o">
'foo'.match('x') # => nil
'foo'.match('f', 1) # => nil
'foo'.match('o', 1) # => #<MatchData "o">
Если блок задан и вычисленное matchdata не равно nil, вызывает блок с matchdata и возвращает значение, возвращённое блоком:
'foo'.match(/o/) {|matchdata| matchdata } # => #<MatchData "o">
Если блок задан, а nil равно matchdata, блок не вызывается:
'foo'.match(/x/) {|matchdata| fail 'Cannot happen' } # => 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);
} Возвращает, найдено ли совпадение для self с заданными аргументами; не обновляет глобальные переменные Regexp.
Вычисляет regexp, преобразуя pattern (если это ещё не Regexp):
regexp = Regexp.new(pattern)
Возвращает true, если self[offset..].match(regexp) возвращает объект MatchData, и false в противном случае:
'foo'.match?(/o/) # => true
'foo'.match?('o') # => true
'foo'.match?(/x/) # => false
'foo'.match?('f', 1) # => false
'foo'.match?('o', 1) # => true
Связано: см. Запросы.
static VALUE
rb_str_oct(VALUE str)
{
return rb_str_to_inum(str, -8, FALSE);
} Интерпретирует начальную подстроку self как восьмеричное, двоичное, десятичное или шестнадцатеричное число, возможно со знаком; возвращает её значение в виде целого числа.
Кратко:
# Interpreted as octal. '777'.oct # => 511 '777x'.oct # => 511 '0777'.oct # => 511 '0o777'.oct # => 511 '-777'.oct # => -511 # Not interpreted as octal. '0b111'.oct # => 7 # Interpreted as binary. '0d999'.oct # => 999 # Interpreted as decimal. '0xfff'.oct # => 4095 # Interpreted as hexadecimal.
Начальная подстрока интерпретируется как восьмеричное число, если начинается с:
-
Одного или нескольких символов, представляющих восьмеричные цифры (каждая в диапазоне
'0'..'7'); интерпретируемая строка заканчивается на первом символе, не являющемся восьмеричной цифрой:'7'.oct @ => 7 '11'.oct # => 9 '777'.oct # => 511 '0777'.oct # => 511 '7778'.oct # => 511 '777x'.oct # => 511
-
'0o', за которым следует одна или несколько восьмеричных цифр:'0o777'.oct # => 511 '0o7778'.oct # => 511
Начальная подстрока не интерпретируется как восьмеричное число, если начинается с:
-
'0b', за которым следует один или несколько символов, представляющих двоичные цифры (каждая в диапазоне'0'..'1'); интерпретируемая строка заканчивается на первом символе, не являющемся двоичной цифрой. Строка интерпретируется как последовательность двоичных цифр (основание 2):'0b111'.oct # => 7 '0b1112'.oct # => 7
-
'0d', за которым следует один или несколько символов, представляющих десятичные цифры (каждая в диапазоне'0'..'9'); интерпретируемая строка заканчивается на первом символе, не являющемся десятичной цифрой. Строка интерпретируется как последовательность десятичных цифр (основание 10):'0d999'.oct # => 999 '0d999x'.oct # => 999
-
'0x', за которым следует один или несколько символов, представляющих шестнадцатеричные цифры (каждая в одном из диапазонов'0'..'9','a'..'f'или'A'..'F'); интерпретируемая строка заканчивается на первом символе, не являющемся шестнадцатеричной цифрой. Строка интерпретируется как последовательность шестнадцатеричных цифр (основание 16):'0xfff'.oct # => 4095 '0xfffg'.oct # => 4095
К любой из описанных выше форм может быть добавлен префикс '-', который меняет знак интерпретируемого значения на противоположный:
'-777'.oct # => -511 '-0777'.oct # => -511 '-0b111'.oct # => -7 '-0xfff'.oct # => -4095
Для любой подстроки, не описанной выше, возвращает ноль:
'foo'.oct # => 0 ''.oct # => 0
Связано: см. Преобразование в нестроковый объект.
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);
} Возвращает целочисленный код первого символа self:
'h'.ord # => 104 'hello'.ord # => 104 'тест'.ord # => 1090 'こんにちは'.ord # => 12371
Связано: см. Преобразование в нестроковый объект.
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));
} Возвращает массив из трёх элементов, содержащих подстроки self.
Если найдено совпадение с pattern, возвращает массив:
[pre_match, first_match, post_match]
где:
-
first_match— первое найденное совпадение. -
pre_matchиpost_match— предшествующая и следующая подстроки.
Если совпадение с pattern не найдено, возвращает массив:
[self.dup, "", ""]
Обратите внимание: в приведённых ниже примерах возвращённая строка 'hello' является копией self, а не self.
Если pattern — это Regexp, выполняет эквивалент self.match(pattern) (также устанавливая переменные сопоставленных данных):
'hello'.partition(/h/) # => ["", "h", "ello"] 'hello'.partition(/l/) # => ["he", "l", "lo"] 'hello'.partition(/l+/) # => ["he", "ll", "o"] 'hello'.partition(/o/) # => ["hell", "o", ""] 'hello'.partition(/^/) # => ["", "", "hello"] 'hello'.partition(//) # => ["", "", "hello"] 'hello'.partition(/$/) # => ["hello", "", ""] 'hello'.partition(/x/) # => ["hello", "", ""]
Если pattern не является Regexp, преобразует его в строку (если это ещё не строка), а затем выполняет эквивалент self.index(pattern) (и не устанавливает глобальные переменные сопоставленных данных):
'hello'.partition('h') # => ["", "h", "ello"]
'hello'.partition('l') # => ["he", "l", "lo"]
'hello'.partition('ll') # => ["he", "ll", "o"]
'hello'.partition('o') # => ["hell", "o", ""]
'hello'.partition('') # => ["", "", "hello"]
'hello'.partition('x') # => ["hello", "", ""]
'тест'.partition('т') # => ["", "т", "ест"]
'こんにちは'.partition('に') # => ["こん", "に", "ちは"]
Связано: см. Преобразование в нестроковый объект.
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;
} Добавляет в начало self конкатенацию заданных other_strings; возвращает self:
'baz'.prepend('foo', 'bar') # => "foobarbaz"
Связано: см. Изменение.
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);
} Заменяет содержимое self содержимым other_string; возвращает self:
s = 'foo' # => "foo"
s.replace('bar') # => "bar"
Связано: см. Изменение.
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_direct(rev, str);
ENC_CODERANGE_SET(rev, cr);
return rev;
} Возвращает новую строку, содержащую символы self в обратном порядке.
'drawer'.reverse # => "reward" 'reviled'.reverse # => "deliver" 'stressed'.reverse # => "desserts" 'semordnilaps'.reverse # => "spalindromes"
Связано: см. Преобразование в новую строку.
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;
} Возвращает self с символами в обратном порядке:
'drawer'.reverse! # => "reward" 'reviled'.reverse! # => "deliver" 'stressed'.reverse! # => "desserts" 'semordnilaps'.reverse! # => "spalindromes"
Связано: см. Изменение.
static VALUE
rb_str_rindex_m(int argc, VALUE *argv, VALUE str)
{
VALUE sub;
VALUE initpos;
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, &initpos) == 2) {
pos = NUM2LONG(initpos);
if (pos < 0 && (pos += len) < 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_enc_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) {
pos = rb_str_sublen(str, pos);
return LONG2NUM(pos);
}
}
return Qnil;
} Возвращает целочисленную позицию последней подстроки, соответствующей заданному аргументу pattern, или nil, если совпадений нет.
Если pattern — строка, возвращает индекс последней совпадающей подстроки в self:
'foo'.rindex('f') # => 0
'foo'.rindex('o') # => 2
'foo'.rindex('oo' # => 1
'foo'.rindex('ooo') # => nil
'тест'.rindex('т') # => 3
'こんにちは'.rindex('ち') # => 3 Если pattern — Regexp, возвращает индекс последнего совпадения в self:
'foo'.rindex(/f/) # => 0 'foo'.rindex(/o/) # => 2 'foo'.rindex(/oo/) # => 1 'foo'.rindex(/ooo/) # => nil
Если offset — неотрицательное число, оно задаёт максимальную начальную позицию в строке, с которой заканчивается поиск:
'foo'.rindex('o', 0) # => nil
'foo'.rindex('o', 1) # => 1
'foo'.rindex('o', 2) # => 2
'foo'.rindex('o', 3) # => 2
При отрицательном целочисленном аргументе offset позиция поиска определяется отсчётом назад от конца self:
'foo'.rindex('o', -1) # => 2
'foo'.rindex('o', -2) # => 1
'foo'.rindex('o', -3) # => nil
'foo'.rindex('o', -4) # => nil
Под последним совпадением понимается совпадение, начинающееся в самой поздней возможной позиции, а не самое длинное из совпадений:
'foo'.rindex(/o+/) # => 2 $~ # => #<MatchData "o">
Чтобы получить последнее самое длинное совпадение, используйте отрицательный просмотр назад:
'foo'.rindex(/(?<!o)o+/) # => 1 $~ # => #<MatchData "oo">
Или String#index с отрицательным просмотром вперёд.
'foo'.index(/o+(?!.*o)/) # => 1 $~ # => #<MatchData "oo">
Связанные разделы: см. Поиск и запросы.
static VALUE
rb_str_rjust(int argc, VALUE *argv, VALUE str)
{
return rb_str_justify(argc, argv, str, 'r');
} Возвращает копию self с выравниванием по правому краю.
Если целочисленный аргумент width больше размера self (в символах), возвращает новую строку длиной width, являющуюся копией self, выровненной по правому краю и дополненной слева символами pad_string:
'hello'.rjust(10) # => " hello" 'hello '.rjust(10) # => " hello " 'hello'.rjust(10, 'ab') # => "ababahello" 'тест'.rjust(10) # => " тест" 'こんにちは'.rjust(10) # => " こんにちは"
Если width <= self.size, возвращает копию self:
'hello'.rjust(5, 'ab') # => "hello" 'hello'.rjust(1, 'ab') # => "hello"
Связанные разделы: см. Преобразование в новую строку.
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;
}
}
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));
} Возвращает массив из 3 элементов — подстрок self.
Ищет в self совпадение с pattern, отыскивая последнее совпадение.
Если pattern не найдено, возвращает массив:
["", "", self.dup]
Если pattern найдено, возвращает массив:
[pre_match, last_match, post_match]
где:
-
last_match— последняя найденная совпадающая подстрока. -
pre_matchиpost_match— предшествующая и следующая подстроки.
Используется следующий шаблон:
-
само
pattern, если этоRegexp. -
Regexp.quote(pattern), еслиpattern— строка.
Обратите внимание, что в приведённых ниже примерах возвращаемая строка 'hello' является копией self, а не self.
Если pattern — Regexp, выполняется поиск последней совпадающей подстроки (при этом также устанавливаются глобальные переменные с данными о совпадениях):
'hello'.rpartition(/l/) # => ["hel", "l", "o"] 'hello'.rpartition(/ll/) # => ["he", "ll", "o"] 'hello'.rpartition(/h/) # => ["", "h", "ello"] 'hello'.rpartition(/o/) # => ["hell", "o", ""] 'hello'.rpartition(//) # => ["hello", "", ""] 'hello'.rpartition(/x/) # => ["", "", "hello"] 'тест'.rpartition(/т/) # => ["тес", "т", ""] 'こんにちは'.rpartition(/に/) # => ["こん", "に", "ちは"]
Если pattern не является Regexp, он преобразуется в строку (если ещё не является ею), после чего выполняется поиск последней совпадающей подстроки (при этом не устанавливаются глобальные переменные с данными о совпадениях):
'hello'.rpartition('l') # => ["hel", "l", "o"]
'hello'.rpartition('ll') # => ["he", "ll", "o"]
'hello'.rpartition('h') # => ["", "h", "ello"]
'hello'.rpartition('o') # => ["hell", "o", ""]
'hello'.rpartition('') # => ["hello", "", ""]
'тест'.rpartition('т') # => ["тес", "т", ""]
'こんにちは'.rpartition('に') # => ["こん", "に", "ちは"]
Связанные разделы: см. Преобразование в нестроковый объект.
static VALUE
rb_str_rstrip(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
char *start;
long olen, roffset;
enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
if (argc > 0) {
char table[TR_TABLE_SIZE];
VALUE del = 0, nodel = 0;
tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
}
else {
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);
} Возвращает копию self с удалёнными конечными пробельными символами; см. раздел Пробельные символы в строках:
whitespace = "\x00\t\n\v\f\r " s = whitespace + 'abc' + whitespace s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r " s.rstrip # => "\u0000\t\n\v\f\r abc"
Если указаны selectors, удаляет символы из selectors в конце self:
s = "---abc+++"
s.rstrip("+") # => "---abc"
selectors должны быть допустимыми селекторами символов (см. раздел Селекторы символов); можно использовать любую допустимую форму, включая отрицание, диапазоны и escape-последовательности:
"01234abc56789".rstrip("0-9") # "01234abc"
"01234abc56789".rstrip("0-9", "^4-6") # "01234abc56"
Связанные разделы: см. Преобразование в новую строку.
static VALUE
rb_str_rstrip_bang(int argc, VALUE *argv, 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);
if (argc > 0) {
char table[TR_TABLE_SIZE];
VALUE del = 0, nodel = 0;
tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
}
else {
roffset = rstrip_offset(str, start, start+olen, enc);
}
if (roffset > 0) {
long len = olen - roffset;
STR_SET_LEN(str, len);
TERM_FILL(start+len, rb_enc_mbminlen(enc));
return str;
}
return Qnil;
} Работает как String#rstrip, за исключением того, что:
-
Удаление выполняется непосредственно в
self(а не в копииself). -
Возвращает
self, если были удалены какие-либо символы, и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;
} Сопоставляет шаблон с self:
-
Если
pattern—Regexp, в качестве шаблона используется самоpattern. -
Если
pattern— строка, в качестве шаблона используетсяRegexp.quote(pattern).
Создаёт коллекцию результатов поиска и обновляет глобальные переменные, связанные с регулярными выражениями:
-
Если шаблон не содержит групп, каждый результат — это совпавшая подстрока.
-
Если шаблон содержит группы, каждый результат — это массив, содержащий совпавшую подстроку для каждой группы.
Если блок не задан, возвращает массив результатов:
'cruel world'.scan(/\w+/) # => ["cruel", "world"]
'cruel world'.scan(/.../) # => ["cru", "el ", "wor"]
'cruel world'.scan(/(...)/) # => [["cru"], ["el "], ["wor"]]
'cruel world'.scan(/(..)(..)/) # => [["cr", "ue"], ["l ", "wo"]]
'тест'.scan(/../) # => ["те", "ст"]
'こんにちは'.scan(/../) # => ["こん", "にち"]
'abracadabra'.scan('ab') # => ["ab", "ab"]
'abracadabra'.scan('nosuch') # => []
Если блок задан, вызывает его для каждого результата и возвращает self:
'cruel world'.scan(/\w+/) {|w| p w }
# => "cruel"
# => "world"
'cruel world'.scan(/(.)(.)/) {|x, y| p [x, y] }
# => ["c", "r"]
# => ["u", "e"]
# => ["l", " "]
# => ["w", "o"]
# => ["r", "l"]
Связанные разделы: см. Преобразование в нестроковый объект.
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, в которой каждая недопустимая последовательность байтов заменена указанной replacement_string.
Если блок не задан, заменяет каждую недопустимую последовательность указанной default_replacement_string (по умолчанию — "�" для кодировки Unicode и '?' в остальных случаях):
"foo\x81\x81bar"scrub # => "foo��bar"
"foo\x81\x81bar".force_encoding('US-ASCII').scrub # => "foo??bar"
"foo\x81\x81bar".scrub('xyzzy') # => "fooxyzzyxyzzybar" Если блок задан, вызывает его для каждой недопустимой последовательности и заменяет эту последовательность значением, возвращённым блоком:
"foo\x81\x81bar".scrub {|sequence| p sequence; 'XYZZY' } # => "fooXYZZYXYZZYbar"
Результат:
"\x81" "\x81"
Связанные разделы: см. Преобразование в новую строку.
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;
} Работает как String#scrub, за исключением того, что:
-
Все замены выполняются непосредственно в
self. -
Возвращает
self.
Связанные разделы: см. Изменение.
VALUE
rb_str_setbyte(VALUE str, VALUE index, VALUE value)
{
long pos = NUM2LONG(index);
long len = RSTRING_LEN(str);
char *ptr, *head, *left = 0;
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));
char byte = (char)(NUM2INT(w) & 0xFF);
if (!str_independent(str))
str_make_independent(str);
enc = STR_ENC_GET(str);
head = RSTRING_PTR(str);
ptr = &head[pos];
if (!STR_EMBED_P(str)) {
cr = ENC_CODERANGE(str);
switch (cr) {
case ENC_CODERANGE_7BIT:
left = 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; возвращает integer:
s = 'xyzzy' s.setbyte(2, 129) # => 129 s # => "xy\x81zy"
Связанные разделы: см. Изменение.
# File lib/shellwords.rb, line 238 def shellescape Shellwords.escape(self) end
Экранирует str, чтобы его можно было безопасно использовать в командной строке оболочки Bourne.
Подробности см. в разделе Shellwords.shellescape.
# File lib/shellwords.rb, line 227 def shellsplit Shellwords.split(self) end
Разбивает str на массив токенов так же, как это делает оболочка UNIX Bourne.
Подробности см. в разделе Shellwords.shellsplit.
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;
} Работает как String#[] (и его псевдоним String#slice), за исключением того, что:
-
Подстановки выполняются непосредственно в
self(а не в копииself). -
Если были внесены изменения, возвращает удалённую подстроку, а в противном случае —
nil.
Несколько примеров:
s = 'hello'
s.slice!('e') # => "e"
s # => "hllo"
s.slice!('e') # => nil
s # => "hllo"
Связанные разделы: см. Изменение.
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), \
str_mod_check(str, str_start, str_len))
beg = 0;
char *ptr = RSTRING_PTR(str);
char *const str_start = ptr;
const long str_len = RSTRING_LEN(str);
char *const eptr = str_start + str_len;
if (split_type == SPLIT_TYPE_AWK) {
char *bptr = ptr;
int skip = 1;
unsigned int c;
if (result) result = rb_ary_new();
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 *substr_start = ptr;
char *sptr = RSTRING_PTR(spat);
long slen = RSTRING_LEN(spat);
if (result) result = rb_ary_new();
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);
str_mod_check(spat, sptr, slen);
ptr += end + slen;
substr_start = ptr;
if (!NIL_P(limit) && lim <= ++i) break;
}
beg = ptr - str_start;
}
else if (split_type == SPLIT_TYPE_CHARS) {
int n;
if (result) result = rb_ary_new_capa(RSTRING_LEN(str));
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 {
if (result) result = rb_ary_new();
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;
} Создаёт массив подстрок, разбивая self при каждом вхождении заданного разделителя полей field_sep.
Если аргументы не указаны, разделение выполняется с использованием разделителя полей $;, значение которого по умолчанию — nil.
Если блок не задан, возвращает массив подстрок:
'abracadabra'.split('a') # => ["", "br", "c", "d", "br"]
Если field_sep равен nil или ' ' (одному пробелу), разделение выполняется при каждой последовательности пробельных символов:
'foo bar baz'.split(nil) # => ["foo", "bar", "baz"]
'foo bar baz'.split(' ') # => ["foo", "bar", "baz"]
"foo \n\tbar\t\n baz".split(' ') # => ["foo", "bar", "baz"]
'foo bar baz'.split(' ') # => ["foo", "bar", "baz"]
''.split(' ') # => []
Если field_sep — пустая строка, разделение выполняется по каждому символу:
'abracadabra'.split('') # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"]
''.split('') # => []
'тест'.split('') # => ["т", "е", "с", "т"]
'こんにちは'.split('') # => ["こ", "ん", "に", "ち", "は"]
Если field_sep — непустая строка, отличная от ' ' (одного пробела), эта строка используется как разделитель:
'abracadabra'.split('a') # => ["", "br", "c", "d", "br"]
'abracadabra'.split('ab') # => ["", "racad", "ra"]
''.split('a') # => []
'тест'.split('т') # => ["", "ес"]
'こんにちは'.split('に') # => ["こん", "ちは"]
Если field_sep — это Regexp, разделение выполняется при каждом вхождении соответствующей подстроки:
'abracadabra'.split(/ab/) # => ["", "racad", "ra"] '1 + 1 == 2'.split(/\W+/) # => ["1", "1", "2"] 'abracadabra'.split(//) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"]
Если регулярное выражение содержит группы, соответствующие им значения включаются в возвращаемый массив:
'1:2:3'.split(/(:)()()/, 2) # => ["1", ":", "", "", "2:3"]
Аргумент limit задаёт ограничение на размер возвращаемого массива; он также определяет, будут ли завершающие пустые строки включены в возвращаемый массив.
Если limit равен нулю, размер массива не ограничен, но завершающие пустые строки опускаются:
'abracadabra'.split('', 0) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"]
'abracadabra'.split('a', 0) # => ["", "br", "c", "d", "br"] # Empty string after last 'a' omitted.
Если limit — положительное целое число, размер массива ограничен (будет выполнено не более n - 1 разделений), а завершающие пустые строки включаются:
'abracadabra'.split('', 3) # => ["a", "b", "racadabra"]
'abracadabra'.split('a', 3) # => ["", "br", "cadabra"]
'abracadabra'.split('', 30) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a", ""]
'abracadabra'.split('a', 30) # => ["", "br", "c", "d", "br", ""]
'abracadabra'.split('', 1) # => ["abracadabra"]
'abracadabra'.split('a', 1) # => ["abracadabra"]
Если limit отрицателен, размер массива не ограничен, а завершающие пустые строки опускаются:
'abracadabra'.split('', -1) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a", ""]
'abracadabra'.split('a', -1) # => ["", "br", "c", "d", "br", ""]
Если задан блок, он вызывается для каждой подстроки и возвращает self:
'foo bar baz'.split(' ') {|substring| p substring }
Вывод:
"foo" "bar" "baz"
Обратите внимание, что приведённый выше пример функционально эквивалентен следующему:
'foo bar baz'.split(' ').each {|substring| p substring }
Вывод:
"foo" "bar" "baz"
Однако последний вариант:
-
Работает медленнее, поскольку создаёт промежуточный массив.
-
Возвращает массив (вместо
self).
Связанные разделы: см. Преобразование в нестроку.
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;
} Возвращает копию self, в которой каждая последовательность (удвоение, утроение и т. д.) указанных символов «сжата» до одного символа.
Последовательности для сжатия задаются аргументами selectors, каждый из которых является строкой; см. Селекторы символов.
Один аргумент может быть одним символом:
'Noooooo!'.squeeze('o') # => "No!"
'foo bar baz'.squeeze(' ') # => "foo bar baz"
'Mississippi'.squeeze('s') # => "Misisippi"
'Mississippi'.squeeze('p') # => "Mississipi"
'Mississippi'.squeeze('x') # => "Mississippi" # Unused selector character is ignored.
'бессонница'.squeeze('с') # => "бесонница"
'бессонница'.squeeze('н') # => "бессоница"
Один аргумент может быть строкой символов:
'Mississippi'.squeeze('sp') # => "Misisipi"
'Mississippi'.squeeze('ps') # => "Misisipi" # Order doesn't matter.
'Mississippi'.squeeze('nonsense') # => "Misisippi" # Unused selector characters are ignored.
Один аргумент может быть диапазоном символов:
'Mississippi'.squeeze('a-p') # => "Mississipi"
'Mississippi'.squeeze('q-z') # => "Misisippi"
'Mississippi'.squeeze('a-z') # => "Misisipi"
Допускается несколько аргументов; см. Несколько селекторов символов.
Связанные разделы: см. Преобразование в новую строку.
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;
} Как String#squeeze, но:
-
Символы сжимаются в
self(а не в копииself). -
Возвращает
self, если были внесены изменения, и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 {
const char *p, *s, *e;
long slen, tlen;
rb_encoding *enc;
StringValue(tmp);
enc = rb_enc_check(str, tmp);
if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
if ((slen = RSTRING_LEN(str)) < tlen) continue;
p = RSTRING_PTR(str);
e = p + slen;
s = p + tlen;
if (!at_char_right_boundary(p, s, e, enc))
continue;
if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
return Qtrue;
}
}
return Qfalse;
} Возвращает значение, указывающее, начинается ли self с любого из заданных patterns.
Для каждого аргумента используется следующий шаблон:
-
Сам шаблон, если это
Regexp. -
Regexp.quote(pattern), если это строка.
Возвращает true, если какой-либо шаблон соответствует началу строки, и false в противном случае:
'hello'.start_with?('hell') # => true
'hello'.start_with?(/H/i) # => true
'hello'.start_with?('heaven', 'hell') # => true
'hello'.start_with?('heaven', 'paradise') # => false
'тест'.start_with?('т') # => true
'こんにちは'.start_with?('こ') # => true
Связанные разделы: см. Проверка.
static VALUE
rb_str_strip(int argc, VALUE *argv, VALUE str)
{
char *start;
long olen, loffset, roffset;
rb_encoding *enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
if (argc > 0) {
char table[TR_TABLE_SIZE];
VALUE del = 0, nodel = 0;
tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
}
else {
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);
} Возвращает копию self без пробельных символов в начале и конце; см. Пробельные символы в строках:
whitespace = "\x00\t\n\v\f\r " s = whitespace + 'abc' + whitespace # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r " s.strip # => "abc"
Если заданы selectors, удаляет символы из selectors с обоих концов self:
s = "---abc+++"
s.strip("-+") # => "abc"
s.strip("+-") # => "abc"
selectors должны быть допустимыми селекторами символов (см. Селекторы символов); можно использовать любую допустимую форму, в том числе отрицание, диапазоны и escape-последовательности:
"01234abc56789".strip("0-9") # "abc"
"01234abc56789".strip("0-9", "^4-6") # "4abc56"
Связанные разделы: см. Преобразование в новую строку.
static VALUE
rb_str_strip_bang(int argc, VALUE *argv, 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);
if (argc > 0) {
char table[TR_TABLE_SIZE];
VALUE del = 0, nodel = 0;
tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
}
else {
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);
TERM_FILL(start+len, rb_enc_mbminlen(enc));
return str;
}
return Qnil;
} Как String#strip, но:
-
Все изменения вносятся в
self. -
Возвращает
self, если были внесены изменения, и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;
} Возвращает копию self, возможно, с заменённой подстрокой.
Аргумент pattern может быть строкой или Regexp; аргумент replacement может быть строкой или Hash.
Разнообразие типов значений аргументов делает этот метод весьма универсальным.
Ниже приведены несколько простых примеров; дополнительные примеры см. в разделе Методы подстановки.
Если заданы аргументы pattern и строка replacement, первая совпавшая подстрока заменяется указанной строкой замены:
s = 'abracadabra' # => "abracadabra"
s.sub('bra', 'xyzzy') # => "axyzzycadabra"
s.sub(/bra/, 'xyzzy') # => "axyzzycadabra"
s.sub('nope', 'xyzzy') # => "abracadabra"
Если заданы аргументы pattern и хеш replacement, первая совпавшая подстрока заменяется значением из указанного хеша замен или удаляется:
h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
s.sub('b', h) # => "aBracadabra"
s.sub(/b/, h) # => "aBracadabra"
s.sub(/d/, h) # => "abracaabra" # 'd' removed.
Если задан аргумент pattern и блок, блок вызывается для каждой совпавшей подстроки; эта подстрока заменяется возвращаемым блоком значением:
s.sub('b') {|match| match.upcase } # => "aBracadabra"
Связанные разделы: см. Преобразование в новую строку.
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_inspect_name(str_enc),
rb_enc_inspect_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);
RB_GC_GUARD(match);
return str;
}
return Qnil;
} Как String#sub, но:
-
Изменения вносятся в
self, а не в копиюself. -
Возвращает
self, если были внесены изменения, и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 # => '**+' 'тест'.succ # => "тесу" 'こんにちは'.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 # => "\x00\x00\x00" s.succ # => "\x00\x00\x01" s = 255.chr * 3 # => "\xFF\xFF\xFF" s.succ # => "\x01\x00\x00\x00"
Перенос может происходить между буквенно-цифровыми символами разных типов и внутри их последовательностей:
s = 'zz99zz99' # => "zz99zz99" s.succ # => "aaa00aa00" s = '99zz99zz' # => "99zz99zz" s.succ # => "100aa00aa"
Следующее значение после пустой String — новая пустая String:
''.succ # => ""
Связанные разделы: см. Преобразование в новую строку.
static VALUE
rb_str_succ_bang(VALUE str)
{
rb_str_modify(str);
str_succ(str);
return str;
} Как String#succ, но изменяет self на месте и возвращает self.
Связанные разделы: см. Изменение.
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-битную контрольную сумму символов в self; контрольная сумма представляет собой сумму двоичных значений каждого байта в self по модулю 2**n - 1:
'hello'.sum # => 532 'hello'.sum(4) # => 4 'hello'.sum(64) # => 532 'тест'.sum # => 1405 'こんにちは'.sum # => 2582
Это не особенно надёжная контрольная сумма.
Связанные разделы: см. Проверка.
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;
} Возвращает строку, содержащую символы из self, с обратным регистром:
-
Каждый символ в верхнем регистре переводится в нижний.
-
Каждый символ в нижнем регистре переводится в верхний.
Примеры:
'Hello'.swapcase # => "hELLO" 'Straße'.swapcase # => "sTRASSE" 'Привет'.swapcase # => "пРИВЕТ" 'RubyGems.org'.swapcase # => "rUBYgEMS.ORG"
Размеры self и результата преобразования в верхний регистр могут различаться:
s = 'Straße' s.size # => 6 s.swapcase # => "sTRASSE" s.swapcase.size # => 7
У некоторых символов (и некоторых наборов символов) нет вариантов в верхнем и нижнем регистре; см. Преобразование регистра:
s = '1, 2, 3, ...' s.swapcase == s # => true s = 'こんにちは' s.swapcase == s # => true
Регистр зависит от заданного mapping, которым может быть :ascii, :fold или :turkic; см. Преобразования регистра.
Связанные методы: см. Преобразование в новую строку.
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, но:
-
Изменения вносятся в
self, а не в копиюself. -
Возвращает
self, если были внесены изменения, иnilв противном случае.
Связанные методы: см. Изменение.
static VALUE
string_to_c(VALUE self)
{
VALUE num;
rb_must_asciicompat(self);
(void)parse_comp(rb_str_fill_terminator(self, 1), FALSE, &num);
return num;
} Возвращает объект Complex: разбирает начальную подстроку self, извлекая два числовых значения, которые становятся координатами комплексного объекта.
Подстрока интерпретируется как содержащая либо прямоугольные координаты (действительную и мнимую части), либо полярные координаты (модуль и угол) — в зависимости от наличия явного или подразумеваемого символа-разделителя:
-
'+','-'или отсутствие разделителя: прямоугольные координаты. -
'@': полярные координаты.
Кратко
В этих примерах мы используем метод Complex#rect для отображения прямоугольных координат, а метод Complex#polar — для отображения полярных координат.
# Rectangular coordinates.
# Real-only: no separator; imaginary part is zero.
'9'.to_c.rect # => [9, 0] # Integer.
'-9'.to_c.rect # => [-9, 0] # Integer (negative).
'2.5'.to_c.rect # => [2.5, 0] # Float.
'1.23e-14'.to_c.rect # => [1.23e-14, 0] # Float with exponent.
'2.5/1'.to_c.rect # => [(5/2), 0] # Rational.
# Some things are ignored.
'foo1'.to_c.rect # => [0, 0] # Unparsed entire substring.
'1foo'.to_c.rect # => [1, 0] # Unparsed trailing substring.
' 1 '.to_c.rect # => [1, 0] # Leading and trailing whitespace.
*
# Imaginary only: trailing 'i' required; real part is zero.
'9i'.to_c.rect # => [0, 9]
'-9i'.to_c.rect # => [0, -9]
'2.5i'.to_c.rect # => [0, 2.5]
'1.23e-14i'.to_c.rect # => [0, 1.23e-14]
'2.5/1i'.to_c.rect # => [0, (5/2)]
# Real and imaginary; '+' or '-' separator; trailing 'i' required.
'2+3i'.to_c.rect # => [2, 3]
'-2-3i'.to_c.rect # => [-2, -3]
'2.5+3i'.to_c.rect # => [2.5, 3]
'2.5+3/2i'.to_c.rect # => [2.5, (3/2)]
# Polar coordinates; '@' separator; magnitude required.
'1.0@0'.to_c.polar # => [1.0, 0.0]
'1.0@'.to_c.polar # => [1.0, 0.0]
"1.0@#{Math::PI}".to_c.polar # => [1.0, 3.141592653589793]
"1.0@#{Math::PI/2}".to_c.polar # => [1.0, 1.5707963267948966] Разбираемые значения
Разбор можно представить как поиск числовых литералов, встроенных в подстроку.
В этом разделе показано, как метод разбирает числовые значения из начальных подстрок. В примерах разбирается только действительная или только мнимая часть; для каждой части разбор выполняется одинаково.
'1foo'.to_c # => (1+0i) # Ignores trailing unparsed characters. ' 1 '.to_c # => (1+0i) # Ignores leading and trailing whitespace. 'x1'.to_c # => (0+0i) # Finds no leading numeric. # Integer literal embedded in the substring. '1'.to_c # => (1+0i) '-1'.to_c # => (-1+0i) '1i'.to_c # => (0+1i) # Integer literals that don't work. '0b100'.to_c # => (0+0i) # Not parsed as binary. '0o100'.to_c # => (0+0i) # Not parsed as octal. '0d100'.to_c # => (0+0i) # Not parsed as decimal. '0x100'.to_c # => (0+0i) # Not parsed as hexadecimal. '010'.to_c # => (10+0i) # Not parsed as octal. # Float literals: '3.14'.to_c # => (3.14+0i) '3.14i'.to_c # => (0+3.14i) '1.23e4'.to_c # => (12300.0+0i) '1.23e+4'.to_c # => (12300.0+0i) '1.23e-4'.to_c # => (0.000123+0i) # Rational literals: '1/2'.to_c # => ((1/2)+0i) '-1/2'.to_c # => ((-1/2)+0i) '1/2r'.to_c # => ((1/2)+0i) '-1/2r'.to_c # => ((-1/2)+0i)
Прямоугольные координаты
При разделителе '+' или '-' либо при отсутствии разделителя значения интерпретируются как прямоугольные координаты: действительная и мнимая части.
При отсутствии разделителя единственное значение присваивается действительной или мнимой части:
''.to_c # => (0+0i) # Defaults to zero. '1'.to_c # => (1+0i) # Real (no trailing 'i'). '1i'.to_c # => (0+1i) # Imaginary (trailing 'i'). 'i'.to_c # => (0+1i) # Special case (imaginary 1).
При разделителе '+' обе части положительны (или равны нулю):
# Without trailing 'i'. '+'.to_c # => (0+0i) # No values: defaults to zero. '+1'.to_c # => (1+0i) # Value after '+': real only. '1+'.to_c # => (1+0i) # Value before '+': real only. '2+1'.to_c # => (2+0i) # Values before and after '+': real and imaginary. # With trailing 'i'. '+1i'.to_c # => (0+1i) # Value after '+': imaginary only. '2+i'.to_c # => (2+1i) # Value before '+': real and imaginary 1. '2+1i'.to_c # => (2+1i) # Values before and after '+': real and imaginary.
При разделителе '-' мнимая часть отрицательна:
# Without trailing 'i'. '-'.to_c # => (0+0i) # No values: defaults to zero. '-1'.to_c # => (-1+0i) # Value after '-': negative real, zero imaginary. '1-'.to_c # => (1+0i) # Value before '-': positive real, zero imaginary. '2-1'.to_c # => (2+0i) # Values before and after '-': positive real, zero imaginary. # With trailing 'i'. '-1i'.to_c # => (0-1i) # Value after '-': negative real, zero imaginary. '2-i'.to_c # => (2-1i) # Value before '-': positive real, negative imaginary. '2-1i'.to_c # => (2-1i) # Values before and after '-': positive real, negative imaginary.
Обратите внимание: вместо символа в конце 'i' можно использовать один из символов 'I', 'j' или 'J' — результат будет тем же.
Полярные координаты
При разделителе '@') значения интерпретируются как полярные координаты: модуль и угол.
'2@'.to_c.polar # => [2, 0.0] # Value before '@': magnitude only.
# Values before and after '@': magnitude and angle.
'2@1'.to_c.polar # => [2.0, 1.0]
"1.0@#{Math::PI/2}".to_c # => (0.0+1i)
"1.0@#{Math::PI}".to_c # => (-1+0.0i)
# Magnitude not given: defaults to zero.
'@'.to_c.polar # => [0, 0.0]
'@1'.to_c.polar # => [0, 0.0]
'1.0@0'.to_c # => (1+0.0i)
Обратите внимание: во всех случаях вместо символа в конце 'i' можно использовать один из символов 'I', 'j', 'J' — результат будет тем же.
static VALUE
rb_str_to_f(VALUE str)
{
return DBL2NUM(rb_str_to_dbl(str, FALSE));
} Returns the result of interpreting leading characters in +self+ as a Float: '3.14159'.to_f # => 3.14159 '1.234e-2'.to_f # => 0.01234 Characters past a leading valid number are ignored: '3.14 (pi to two places)'.to_f # => 3.14 Returns zero if there is no leading valid number: 'abcdef'.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);
} Возвращает результат интерпретации начальных символов self как целого числа в заданной системе счисления base; base должно быть равно 0 или находиться в диапазоне (2..36):
'123456'.to_i # => 123456 '123def'.to_i(16) # => 1195503
Если задано base, строка object может содержать начальные символы, указывающие фактическую систему счисления:
'123def'.to_i(0) # => 123 '0123def'.to_i(0) # => 83 '0b123def'.to_i(0) # => 1 '0o123def'.to_i(0) # => 83 '0d123def'.to_i(0) # => 123 '0x123def'.to_i(0) # => 1195503
Символы после начального корректного числа (в заданной системе счисления base) игнорируются:
'12.345'.to_i # => 12 '12345'.to_i(2) # => 1
Возвращает ноль, если начальное корректное число отсутствует:
'abcdef'.to_i # => 0 '2'.to_i(2) # => 0
Связанные методы: см. Преобразование в объект, не являющийся строкой.
# File ext/json/lib/json/add/string.rb, line 32 def to_json_raw(...) to_json_raw_object.to_json(...) end
Этот метод создает текст JSON на основе результата вызова to_json_raw_object для этого объекта String.
# File ext/json/lib/json/add/string.rb, line 21
def to_json_raw_object
{
JSON.create_id => self.class.name,
"raw" => unpack("C*"),
}
end Этот метод создает необработанный хеш-объект, который можно включать в другие структуры данных и который будет сгенерирован как необработанная строка. Этот метод следует использовать, если требуется преобразовать необработанные строки в JSON, а не в строки UTF-8, например для двоичных данных.
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;
} Возвращает результат интерпретации начальных символов self как рационального числа:
'123'.to_r # => (123/1) # Integer literal. '300/2'.to_r # => (150/1) # Rational literal. '-9.2'.to_r # => (-46/5) # Float literal. '-9.2e2'.to_r # => (-920/1) # Float literal.
Игнорирует начальные и конечные пробелы, а также завершающие нечисловые символы:
' 2 '.to_r # => (2/1) '21-Jun-09'.to_r # => (21/1)
Возвращает рациональный ноль, если начальные числовые символы отсутствуют.
'BWV 1079'.to_r # => (0/1)
ПРИМЕЧАНИЕ: '0.3'.to_r эквивалентно 3/10r, но отличается от 0.3.to_r:
'0.3'.to_r # => (3/10) 3/10r # => (3/10) 0.3.to_r # => (5404319552844595/18014398509481984)
Связанные методы: см. Преобразование в объект, не являющийся строкой.
static VALUE
rb_str_to_s(VALUE str)
{
if (rb_obj_class(str) != rb_cString) {
return str_duplicate(rb_cString, str);
}
return str;
} Возвращает self, если self является String, или self, преобразованный в String, если self является подклассом String.
Связанные методы: см. Преобразование в новую строку.
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;
} Возвращает копию self, заменяя каждый символ, указанный в строке selector, соответствующим символом в строке replacements. Соответствие определяется позицией:
-
Каждое вхождение первого символа, указанного в
selector, заменяется первым символом вreplacements. -
Каждое вхождение второго символа, указанного в
selector, заменяется вторым символом вreplacements. -
И так далее.
Пример:
'hello'.tr('el', 'ip') #=> "hippo"
Если replacements короче, чем selector, он неявно дополняется своим последним символом:
'hello'.tr('aeiou', '-') # => "h-ll-"
'hello'.tr('aeiou', 'AA-') # => "hAll-"
Аргументы selector и replacements должны быть допустимыми селекторами символов (см. Селекторы символов) и могут использовать любые допустимые формы, включая отрицание, диапазоны и escape-последовательности:
'hello'.tr('^aeiou', '-') # => "-e--o" # Negation.
'ibm'.tr('b-z', 'a-z') # => "hal" # Range.
'hel^lo'.tr('\^aeiou', '-') # => "h-l-l-" # Escaped leading caret.
'i-b-m'.tr('b\-z', 'a-z') # => "ibabm" # Escaped embedded hyphen.
'foo\\bar'.tr('ab\\', 'XYZ') # => "fooZYXr" # Escaped backslash.
Связанные методы: см. Преобразование в новую строку.
static VALUE
rb_str_tr_bang(VALUE str, VALUE src, VALUE repl)
{
return tr_trans(str, src, repl, 0);
} 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;
} Как String#tr, но:
-
Также удаляет повторяющиеся символы в измененных частях преобразованной строки; см.
String#squeeze. -
Возвращает преобразованную строку с удаленными повторяющимися символами.
Примеры:
'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, но:
-
Изменяет
selfна месте (а не его копиюself). -
Возвращает
self, если были внесены изменения, и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);
}
}
RB_GC_GUARD(str);
return undumped;
invalid_format:
rb_raise(rb_eRuntimeError, "invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
} Обратная операция к String#dump; возвращает копию self, отменяя изменения, выполненные методом String#dump.
Связанные материалы: см. Преобразование в новую строку.
static VALUE
rb_str_unicode_normalize(int argc, VALUE *argv, VALUE str)
{
return unicode_normalize_common(argc, argv, str, id_normalize);
} Возвращает копию self с применённой нормализацией Unicode.
Аргумент form должен быть одним из следующих символов (см. формы нормализации Unicode):
-
:nfc: каноническое разложение с последующей канонической композицией. -
:nfd: каноническое разложение. -
:nfkc: разложение по совместимости с последующей канонической композицией. -
:nfkd: разложение по совместимости.
Кодировка self должна быть одной из следующих:
-
Encoding::UTF_8. -
Encoding::UTF_16BE. -
Encoding::UTF_16LE. -
Encoding::UTF_32BE. -
Encoding::UTF_32LE. -
Encoding::GB18030. -
Encoding::UCS_2BE. -
Encoding::UCS_4BE.
Примеры:
"a\u0300".unicode_normalize # => "à" # Lowercase 'a' with grave accens. "a\u0300".unicode_normalize(:nfd) # => "à" # Same.
Связанные материалы: см. Преобразование в новую строку.
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, но нормализация выполняется непосредственно над self (а не над его копией self).
Связанные материалы: см. Изменение.
static VALUE
rb_str_unicode_normalized_p(int argc, VALUE *argv, VALUE str)
{
return unicode_normalize_common(argc, argv, str, id_normalized_p);
} Возвращает информацию о том, находится ли self в указанной form нормализации Unicode; см. String#unicode_normalize.
Значение form должно быть одним из :nfc, :nfd, :nfkc или :nfkd.
Примеры:
"a\u0300".unicode_normalized? # => false "a\u0300".unicode_normalized?(:nfd) # => true "\u00E0".unicode_normalized? # => true "\u00E0".unicode_normalized?(:nfd) # => false
Вызывает исключение, если self не имеет кодировки Unicode:
s = "\xE0".force_encoding(Encoding::ISO_8859_1) s.unicode_normalized? # Raises Encoding::CompatibilityError
Связанные материалы: см. Проверка.
# File pack.rb, line 25 def unpack(fmt, offset: 0) Primitive.attr! :use_block Primitive.pack_unpack(fmt, offset) end
Извлекает данные из self для создания новых объектов; см. Упакованные данные.
Если передан блок, вызывает его для каждого распакованного объекта.
Если блок не передан, возвращает массив, содержащий распакованные объекты.
Связанные материалы: см. Преобразование в объект, не являющийся строкой.
# File pack.rb, line 37 def unpack1(fmt, offset: 0) Primitive.pack_unpack1(fmt, offset) end
Подобно String#unpack без блока, но распаковывает и возвращает только первый извлечённый объект. См. Упакованные данные.
Связанные материалы: см. Преобразование в объект, не являющийся строкой.
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_direct(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;
} Возвращает новую строку, содержащую символы self в верхнем регистре:
'hello'.upcase # => "HELLO" 'straße'.upcase # => "STRASSE" 'привет'.upcase # => "ПРИВЕТ" 'RubyGems.org'.upcase # => "RUBYGEMS.ORG"
Длины self и результата преобразования в верхний регистр могут различаться:
s = 'Straße' s.size # => 6 s.upcase # => "STRASSE" s.upcase.size # => 7
У некоторых символов (и некоторых наборов символов) нет вариантов в верхнем и нижнем регистре; см. Изменение регистра:
s = '1, 2, 3, ...' s.upcase == s # => true s = 'こんにちは' s.upcase == s # => true
Преобразование регистра зависит от указанного mapping, которым может быть :ascii, :fold или :turkic; см. Преобразования регистра.
Связанные материалы: см. Преобразование в новую строку.
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;
} Подобно String#upcase, но:
-
Изменяет регистр символов непосредственно в
self(а не в его копииself). -
Возвращает
self, если были внесены изменения, иначе возвращаетnil.
Связанные материалы: см. Изменение.
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, возвращаемого последовательными вызовами String#succ; первое значение — self, следующее — self.succ и так далее; последовательность завершается при достижении значения other_string; возвращает self:
a = []
'a'.upto('f') {|c| a.push(c) }
a # => ["a", "b", "c", "d", "e", "f"]
a = []
'Ж'.upto('П') {|c| a.push(c) }
a # => ["Ж", "З", "И", "Й", "К", "Л", "М", "Н", "О", "П"]
a = []
'よ'.upto('ろ') {|c| a.push(c) }
a # => ["よ", "ら", "り", "る", "れ", "ろ"]
a = []
'a8'.upto('b6') {|c| a.push(c) }
a # => ["a8", "a9", "b0", "b1", "b2", "b3", "b4", "b5", "b6"]
Если аргумент exclusive задан как истинный объект, последнее значение пропускается:
a = []
'a'.upto('f', true) {|c| a.push(c) }
a # => ["a", "b", "c", "d", "e"]
Если 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 RBOOL(cr != ENC_CODERANGE_BROKEN);
} Возвращает информацию о том, правильно ли закодирован self:
s = 'Straße' s.valid_encoding? # => true s.encoding # => #<Encoding:UTF-8> s.force_encoding(Encoding::ASCII).valid_encoding? # => false
Связанные материалы: см. Проверка.
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.