класс StringScanner
Класс StringScanner поддерживает обработку сохранённой строки как потока; этот код создаёт новый объект StringScanner с строкой 'foobarbaz':
require 'strscan'
scanner = StringScanner.new('foobarbaz')
О примерах
Все примеры здесь предполагают, что StringScanner был запрошен:
require 'strscan'
Некоторые примеры здесь предполагают, что эти константы определены:
MULTILINE_TEXT = <<~EOT Go placidly amid the noise and haste, and remember what peace there may be in silence. EOT HIRAGANA_TEXT = 'こんにちは' ENGLISH_TEXT = 'Hello'
Некоторые примеры здесь предполагают, что определены некоторые вспомогательные методы:
-
put_situation(scanner): Отображает значения методов сканераpos,charpos,restиrest_size. -
put_match_values(scanner): Отображает значения совпадений сканера. -
match_values_cleared?(scanner): Возвращает, очищены ли значения совпадений сканера.
См. примеры [здесь].
Объект StringScanner
Этот код создаёт объект StringScanner (назовём его просто сканером) и демонстрирует некоторые его базовые свойства:
scanner = StringScanner.new('foobarbaz')
scanner.string # => "foobarbaz"
put_situation(scanner)
# Situation:
# pos: 0
# charpos: 0
# rest: "foobarbaz"
# rest_size: 9
Сканер имеет:
-
Сохранённую строку, которая:
-
Изначально устанавливается методом
StringScanner.new(string)в заданнуюstring('foobarbaz'в примере выше). -
Модифицируется методами
string=(new_string)иconcat(more_string). -
Возвращается методом
string.
Подробнее см. Сохранённую строку ниже.
-
-
Позицию; индекс с нуля в байтах сохранённой строки (не в её символах):
-
Изначально устанавливается методом
StringScanner.newв0. -
Возвращается методом
pos. -
Модифицируется явно методами
reset,terminateиpos=(new_pos). -
Модифицируется неявно (различными методами перемещения и другими).
Подробнее см. Позицию байта ниже.
-
-
Целевой подстроку, которая является подстрокой сохранённой строки; она простирается от текущей позиции до конца сохранённой строки:
-
Изначально устанавливается методом
StringScanner.new(string)в заданнуюstring('foobarbaz'в примере выше). -
Возвращается методом
rest. -
Модифицируется любыми изменениями либо сохранённой строки, либо позиции.
Самое важное: методы поиска и перемещения работают с целевой подстрокой, которая может быть (и часто является) меньше всей сохранённой строки.
Подробнее см. Целевую подстроку ниже.
-
Сохранённая строка
Сохранённая строка — это строка, сохранённая в объекте StringScanner.
Каждый из этих методов устанавливает, изменяет или возвращает сохранённую строку:
Method | Эффект |
|---|---|
::new(string) | Создаёт новый сканер для данной строки. |
string=(new_string) | Заменяет существующую сохранённую строку. |
concat(more_string) | Добавляет строку к существующей сохранённой строке. |
string | Возвращает сохранённую строку. |
Позиции
Объект StringScanner поддерживает нулевую байтовую позицию и нулевую символическую позицию.
Каждый из этих методов явно устанавливает позиции:
Method | Эффект |
|---|---|
reset | Устанавливает обе позиции в ноль (начало сохранённой строки). |
terminate | Устанавливает обе позиции в конец сохранённой строки. |
pos=(new_byte_position) | Устанавливает байтовую позицию; корректирует позицию символа. |
Байтовая позиция (Позиция)
Байтовая позиция (или просто позиция) — это нулевой индекс в байтах сохранённой строки сканера; для нового объекта StringScanner байтовая позиция равна нулю.
Когда байтовая позиция:
-
Ноль (в начале), целевая подстрока — это вся сохранённая строка.
-
Равна размеру сохранённой строки (в конце), целевая подстрока — это пустая строка
''.
Для получения или установки байтовой позиции:
-
pos: возвращает байтовую позицию. -
pos=(new_pos): устанавливает байтовую позицию.
Многие методы используют байтовую позицию в качестве основы для поиска совпадений; многие другие устанавливают, увеличивают или уменьшают байтовую позицию:
scanner = StringScanner.new('foobar')
scanner.pos # => 0
scanner.scan(/foo/) # => "foo" # Match found.
scanner.pos # => 3 # Byte position incremented.
scanner.scan(/foo/) # => nil # Match not found.
scanner.pos # => 3 # Byte position not changed.
Некоторые методы неявно изменяют байтовую позицию; см.:
Значения этих методов выводятся непосредственно из значений pos и string:
-
rest_size:rest.size.
Позиция символа
Позиция символа — это нулевой индекс в символах сохранённой строки; для нового объекта StringScanner позиция символа равна нулю.
Метод charpos возвращает позицию символа; её значение нельзя явно сбросить.
Некоторые методы изменяют (увеличивают или сбрасывают) позицию символа; см.:
Пример (строка включает многобайтовые символы):
scanner = StringScanner.new(ENGLISH_TEXT) # Five 1-byte characters. scanner.concat(HIRAGANA_TEXT) # Five 3-byte characters scanner.string # => "Helloこんにちは" # Twenty bytes in all. put_situation(scanner) # Situation: # pos: 0 # charpos: 0 # rest: "Helloこんにちは" # rest_size: 20 scanner.scan(/Hello/) # => "Hello" # Five 1-byte characters. put_situation(scanner) # Situation: # pos: 5 # charpos: 5 # rest: "こんにちは" # rest_size: 15 scanner.getch # => "こ" # One 3-byte character. put_situation(scanner) # Situation: # pos: 8 # charpos: 6 # rest: "んにちは" # rest_size: 12
Целевая подстрока
Целевая подстрока — это часть сохранённой строки, которая простирается от текущей байтовой позиции до конца сохранённой строки; она всегда либо:
-
Вся сохранённая строка (байтовая позиция — ноль).
-
Конечная подстрока сохранённой строки (байтовая позиция положительна).
Целевая подстрока возвращается методом rest, а её размер возвращается методом rest_size.
Примеры:
scanner = StringScanner.new('foobarbaz')
put_situation(scanner)
# Situation:
# pos: 0
# charpos: 0
# rest: "foobarbaz"
# rest_size: 9
scanner.pos = 3
put_situation(scanner)
# Situation:
# pos: 3
# charpos: 3
# rest: "barbaz"
# rest_size: 6
scanner.pos = 9
put_situation(scanner)
# Situation:
# pos: 9
# charpos: 9
# rest: ""
# rest_size: 0
Установка целевой подстроки
Целевая подстрока устанавливается всякий раз, когда:
-
Сохранённая строка устанавливается (позиция сбрасывается в ноль; целевая подстрока устанавливается в сохранённую строку).
-
Байтовая позиция устанавливается (целевая подстрока корректируется соответственно).
Запрос целевой подстроки
Эта таблица обобщает (подробности и примеры см. по ссылкам):
Method | Возвращает |
|---|---|
rest | Целевая подстрока. |
rest_size | Размер (в байтах) целевой подстроки. |
Поиск в целевой подстроке
Метод поиска проверяет целевую подстроку, но не перемещает позиции или (по умолчанию) не сокращает целевую подстроку.
Эта таблица обобщает (подробности и примеры см. по ссылкам):
Method | Возвращает | Устанавливает значения соответствия? |
|---|---|---|
check(pattern) | Совпавший начальный подстрока или nil. | Да. |
check_until(pattern) | Совпавшая подстрока (в любом месте) или nil. | Да. |
exist?(pattern) | Индекс конца совпавшей подстроки (в любом месте). | Да. |
match?(pattern) | Размер совпавшей начальной подстроки или nil. | Да. |
peek(size) | Начальная подстрока заданной длины (байты). | Нет. |
peek_byte |
Integer ведущий байт или nil. | Нет. |
rest | Целевая подстрока (с позиции байта до конца). | Нет. |
Перемещение по целевой подстроке
Метод перемещения проверяет целевую подстроку и, если успешно:
-
Перемещает позиции.
-
Укорачивает целевую подстроку.
В этой таблице обобщены (подробности и примеры по ссылкам):
Method | Возвращает | Устанавливает значения соответствия? |
|---|---|---|
get_byte | Ведущая байт или nil. | Нет. |
getch | Ведущая символ или nil. | Нет. |
scan(pattern) | Совпавший начальный подстрока или nil. | Да. |
scan_byte |
Integer ведущий байт или nil. | Нет. |
scan_until(pattern) | Совпавшая подстрока (в любом месте) или nil. | Да. |
skip(pattern) | Размер совпавшей начальной подстроки или nil. | Да. |
skip_until(pattern) | Разница позиций до конца совпавшей подстроки или nil. | Да. |
unscan |
self. | Нет. |
Запросы к сканеру
Каждый из этих методов запрашивает объект сканера без его изменения (подробности и примеры по ссылкам)
Method | Возвращает |
|---|---|
beginning_of_line? |
true или false. |
charpos | Позиция символа. |
eos? |
true или false. |
fixed_anchor? |
true или false. |
inspect |
String представление self. |
pos | Позиция байта. |
rest | Целевая подстрока. |
rest_size | Размер целевой подстроки. |
string | Хранимый строка. |
Сопоставление
StringScanner реализует сопоставление шаблонов через Ruby класс Regexp, и его поведение сопоставления такое же, как у Ruby, за исключением свойства фиксированного якоря.
Методы сопоставления
Каждый метод сопоставления принимает один аргумент pattern, и пытается найти совпадающую подстроку в целевой подстроке.
Method | Тип шаблона | Сопоставляет с целевой подстрокой | Возвращаемое значение при успехе | Может обновлять позиции? |
|---|---|---|---|---|
check |
Regexp или String. | В начале. | Совпавшая подстрока. | Нет. |
check_until |
Regexp или String. | В любом месте. | Подстрока. | Нет. |
match? |
Regexp или String. | В начале. | Размер соответствия. | Нет. |
exist? |
Regexp или String. | В любом месте. | Размер подстроки. | Нет. |
scan |
Regexp или String. | В начале. | Совпавшая подстрока. | Да. |
scan_until |
Regexp или String. | В любом месте. | Подстрока. | Да. |
skip |
Regexp или String. | В начале. | Размер соответствия. | Да. |
skip_until |
Regexp или String. | В любом месте. | Размер подстроки. | Да. |
Выбор метода сопоставления зависит от:
-
Где вы хотите найти совпадение:
-
Только в начале целевой подстроки:
check,match?,scan,skip. -
В любом месте целевой подстроки:
check_until,exist?,scan_until,skip_until.
-
-
Нужно ли:
-
Перемещаться, изменяя позиции:
scan,scan_until,skip,skip_until. -
Сохранить позиции неизменными:
check,check_until,match?,exist?.
-
-
Что вы хотите получить в качестве возвращаемого значения:
-
Подстроку:
check_until,scan_until. -
Размер подстроки:
exist?,skip_until.
Значения соответствия
Значения соответствия в объекте StringScanner обычно содержат результаты последнего проведенного сопоставления.
Каждое значение соответствия можно рассматривать как:
-
Пустое: Изначально или после неудачной попытки сопоставления: обычно
false,nil, или{}. -
Заполненное: После успешной попытки сопоставления:
true, строка, массив или хэш.
Каждый из этих методов очищает значения соответствия:
Каждый из этих методов пытается сопоставить шаблон и либо устанавливает значения соответствия (если успешно), либо очищает их (если нет):
Основные значения соответствия
Основные значения соответствия — это те, которые не связаны с захватом.
Каждый из этих методов возвращает основное значение соответствия:
Method | Возвращаемое значение после совпадения | Возвращаемое значение после отсутствия совпадения |
|---|---|---|
matched? |
true. |
false. |
matched_size | Размер совпавшей подстроки. |
nil. |
matched | Совпавшая подстрока. |
nil. |
pre_match | Подстрока, предшествующая совпавшей подстроке. |
nil. |
post_match | Подстрока, следующая за совпавшей подстрокой. |
nil. |
См. примеры ниже.
Значения захваченных совпадений
Значения захваченных совпадений относятся к группировкам.
Каждый из этих методов возвращает значение захваченного совпадения:
Method | Возвращаемое значение после совпадения | Возвращаемое значение после отсутствия совпадения |
|---|---|---|
size | Количество захваченных подстрок. |
nil. |
[](n) |
n-я захваченная подстрока. |
nil. |
captures |
Array всех захваченных подстрок. |
nil. |
values_at(*n) |
Array указанных захваченных подстрок. |
nil. |
named_captures |
Hash именованных захватов. |
{}. |
См. примеры ниже.
Примеры значений совпадений
Успешная попытка базового совпадения (без захватов):
scanner = StringScanner.new('foobarbaz')
scanner.exist?(/bar/)
put_match_values(scanner)
# Basic match values:
# matched?: true
# matched_size: 3
# pre_match: "foo"
# matched : "bar"
# post_match: "baz"
# Captured match values:
# size: 1
# captures: []
# named_captures: {}
# values_at: ["bar", nil]
# []:
# [0]: "bar"
# [1]: nil
Неуспешная попытка базового совпадения (без захватов);
scanner = StringScanner.new('foobarbaz')
scanner.exist?(/nope/)
match_values_cleared?(scanner) # => true
Успешная попытка совпадения с незаданными захватами:
scanner = StringScanner.new('foobarbazbatbam')
scanner.exist?(/(foo)bar(baz)bat(bam)/)
put_match_values(scanner)
# Basic match values:
# matched?: true
# matched_size: 15
# pre_match: ""
# matched : "foobarbazbatbam"
# post_match: ""
# Captured match values:
# size: 4
# captures: ["foo", "baz", "bam"]
# named_captures: {}
# values_at: ["foobarbazbatbam", "foo", "baz", "bam", nil]
# []:
# [0]: "foobarbazbatbam"
# [1]: "foo"
# [2]: "baz"
# [3]: "bam"
# [4]: nil
Успешная попытка совпадения с именованными захватами; то же, что и выше, но с named_captures:
scanner = StringScanner.new('foobarbazbatbam')
scanner.exist?(/(?<x>foo)bar(?<y>baz)bat(?<z>bam)/)
scanner.named_captures # => {"x"=>"foo", "y"=>"baz", "z"=>"bam"}
Неуспешная попытка совпадения с незаданными захватами:
scanner = StringScanner.new('somestring')
scanner.exist?(/(foo)bar(baz)bat(bam)/)
match_values_cleared?(scanner) # => true
Неуспешная попытка совпадения с именованными захватами; то же, что и выше, но с named_captures:
scanner = StringScanner.new('somestring')
scanner.exist?(/(?<x>foo)bar(?<y>baz)bat(?<z>bam)/)
match_values_cleared?(scanner) # => false
scanner.named_captures # => {"x"=>nil, "y"=>nil, "z"=>nil}
Свойство фиксированного якоря
Сопоставление шаблонов в StringScanner такое же, как и в Ruby, за исключением свойства фиксированного якоря, которое определяет значение '\A':
-
false(по умолчанию): соответствует текущей позиции байта.scanner = StringScanner.new('foobar') scanner.scan(/\A./) # => "f" scanner.scan(/\A./) # => "o" scanner.scan(/\A./) # => "o" scanner.scan(/\A./) # => "b" -
true: соответствует началу целевой подстроки; никогда не соответствует, если позиция байта не ноль:scanner = StringScanner.new('foobar', fixed_anchor: true) scanner.scan(/\A./) # => "f" scanner.scan(/\A./) # => nil scanner.reset scanner.scan(/\A./) # => "f"
Свойство фиксированного якоря устанавливается при создании объекта StringScanner и не может быть изменено (см. StringScanner.new); метод fixed_anchor? возвращает это значение.
Публичные методы класса
Исходный код
static VALUE
strscan_initialize(int argc, VALUE *argv, VALUE self)
{
struct strscanner *p;
VALUE str, options;
p = check_strscan(self);
rb_scan_args(argc, argv, "11", &str, &options);
options = rb_check_hash_type(options);
if (!NIL_P(options)) {
VALUE fixed_anchor;
ID keyword_ids[1];
keyword_ids[0] = rb_intern("fixed_anchor");
rb_get_kwargs(options, keyword_ids, 0, 1, &fixed_anchor);
if (fixed_anchor == Qundef) {
p->fixed_anchor_p = false;
}
else {
p->fixed_anchor_p = RTEST(fixed_anchor);
}
}
else {
p->fixed_anchor_p = false;
}
StringValue(str);
p->str = str;
return self;
} Возвращает новый объект StringScanner, у которого сохранённая строка — заданная string; устанавливает свойство фиксированного якоря:
scanner = StringScanner.new('foobarbaz')
scanner.string # => "foobarbaz"
scanner.fixed_anchor? # => false
put_situation(scanner)
# Situation:
# pos: 0
# charpos: 0
# rest: "foobarbaz"
# rest_size: 9
Общедоступные методы экземпляра
Исходный код
static VALUE
strscan_aref(VALUE self, VALUE idx)
{
const char *name;
struct strscanner *p;
long i;
GET_SCANNER(self, p);
if (! MATCHED_P(p)) return Qnil;
switch (TYPE(idx)) {
case T_SYMBOL:
idx = rb_sym2str(idx);
/* fall through */
case T_STRING:
if (!RTEST(p->regex)) return Qnil;
RSTRING_GETMEM(idx, name, i);
i = name_to_backref_number(&(p->regs), p->regex, name, name + i, rb_enc_get(idx));
break;
default:
i = NUM2LONG(idx);
}
if (i < 0)
i += p->regs.num_regs;
if (i < 0) return Qnil;
if (i >= p->regs.num_regs) return Qnil;
if (p->regs.beg[i] == -1) return Qnil;
return extract_range(p,
adjust_register_position(p, p->regs.beg[i]),
adjust_register_position(p, p->regs.end[i]));
} Возвращает захваченную подстроку или nil; см. Захваченные значения совпадения.
Когда есть захват:
scanner = StringScanner.new('Fri Dec 12 1975 14:39')
scanner.scan(/(?<wday>\w+) (?<month>\w+) (?<day>\d+) /)
-
specifierноль: возвращает всю совпавшую подстроку:scanner[0] # => "Fri Dec 12 " scanner.pre_match # => "" scanner.post_match # => "1975 14:39"
-
specifierположительное целое число. возвращаетn-й захват илиnil, если он вне диапазона:scanner[1] # => "Fri" scanner[2] # => "Dec" scanner[3] # => "12" scanner[4] # => nil
-
specifierотрицательное целое число. считает назад от последней подгруппы:scanner[-1] # => "12" scanner[-4] # => "Fri Dec 12 " scanner[-5] # => nil
-
specifierсимвол или строка. возвращает именованную подгруппу илиnil, если такой нет:scanner[:wday] # => "Fri" scanner['wday'] # => "Fri" scanner[:month] # => "Dec" scanner[:day] # => "12" scanner[:nope] # => nil
Когда нет захватов, только [0] возвращает ненулевое %%%CODE_BLOCK_243%%:
scanner = StringScanner.new('foobarbaz')
scanner.exist?(/bar/)
scanner[0] # => "bar"
scanner[1] # => nil
При неудачном сопоставлении даже [0] возвращает nil:
scanner.scan(/nope/) # => nil scanner[0] # => nil scanner[1] # => nil
Исходный код
static VALUE
strscan_bol_p(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
if (CURPTR(p) > S_PEND(p)) return Qnil;
if (p->curr == 0) return Qtrue;
return (*(CURPTR(p) - 1) == '\n') ? Qtrue : Qfalse;
} Возвращает, находится ли позиция в начале строки; то есть, в начале сохранённой строки или сразу после новой строки:
scanner = StringScanner.new(MULTILINE_TEXT)
scanner.string
# => "Go placidly amid the noise and haste,\nand remember what peace there may be in silence.\n"
scanner.pos # => 0
scanner.beginning_of_line? # => true
scanner.scan_until(/,/) # => "Go placidly amid the noise and haste,"
scanner.beginning_of_line? # => false
scanner.scan(/\n/) # => "\n"
scanner.beginning_of_line? # => true
scanner.terminate
scanner.beginning_of_line? # => true
scanner.concat('x')
scanner.terminate
scanner.beginning_of_line? # => false
StringScanner#bol? является псевдонимом для StringScanner#beginning_of_line?.
Исходный код
static VALUE
strscan_captures(VALUE self)
{
struct strscanner *p;
int i, num_regs;
VALUE new_ary;
GET_SCANNER(self, p);
if (! MATCHED_P(p)) return Qnil;
num_regs = p->regs.num_regs;
new_ary = rb_ary_new2(num_regs);
for (i = 1; i < num_regs; i++) {
VALUE str;
if (p->regs.beg[i] == -1)
str = Qnil;
else
str = extract_range(p,
adjust_register_position(p, p->regs.beg[i]),
adjust_register_position(p, p->regs.end[i]));
rb_ary_push(new_ary, str);
}
return new_ary;
} Возвращает массив захваченных значений совпадения по индексам (1..) , если последнее попытка сопоставления прошла успешно, или nil в противном случае:
scanner = StringScanner.new('Fri Dec 12 1975 14:39')
scanner.captures # => nil
scanner.exist?(/(?<wday>\w+) (?<month>\w+) (?<day>\d+) /)
scanner.captures # => ["Fri", "Dec", "12"]
scanner.values_at(*0..4) # => ["Fri Dec 12 ", "Fri", "Dec", "12", nil]
scanner.exist?(/Fri/)
scanner.captures # => []
scanner.scan(/nope/)
scanner.captures # => nil
Исходный код
static VALUE
strscan_get_charpos(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
return LONG2NUM(rb_enc_strlen(S_PBEG(p), CURPTR(p), rb_enc_get(p->str)));
} вызов: charpos -> позиция_символа
Возвращает позицию символа (по умолчанию ноль), которая может отличаться от байтовой позиции, указанной методом pos:
scanner = StringScanner.new(HIRAGANA_TEXT) scanner.string # => "こんにちは" scanner.getch # => "こ" # 3-byte character. scanner.getch # => "ん" # 3-byte character. put_situation(scanner) # Situation: # pos: 6 # charpos: 2 # rest: "にちは" # rest_size: 9
Исходный код
static VALUE
strscan_check(VALUE self, VALUE re)
{
return strscan_do_scan(self, re, 0, 1, 1);
} Попытка сопоставить заданный pattern в начале целевой подстроки; не изменяет позиций.
Если сопоставление успешно:
-
Возвращает совпавшую подстроку.
-
Устанавливает все значения совпадения.
scanner = StringScanner.new('foobarbaz')
scanner.pos = 3
scanner.check('bar') # => "bar"
put_match_values(scanner)
# Basic match values:
# matched?: true
# matched_size: 3
# pre_match: "foo"
# matched : "bar"
# post_match: "baz"
# Captured match values:
# size: 1
# captures: []
# named_captures: {}
# values_at: ["bar", nil]
# []:
# [0]: "bar"
# [1]: nil
# => 0..1
put_situation(scanner)
# Situation:
# pos: 3
# charpos: 3
# rest: "barbaz"
# rest_size: 6
Если сопоставление не удалось:
-
Возвращает
nil. -
Очищает все значения совпадения.
scanner.check(/nope/) # => nil match_values_cleared?(scanner) # => true
Исходный код
static VALUE
strscan_check_until(VALUE self, VALUE re)
{
return strscan_do_scan(self, re, 0, 1, 0);
} Попытка сопоставить заданный pattern где угодно (в любой позиции) в целевой подстроке; не изменяет позиции.
Если сопоставление успешно:
-
Устанавливает все значения совпадения.
-
Возвращает совпавшую подстроку, которая простирается от текущей позиции до конца совпавшей подстроки.
scanner = StringScanner.new('foobarbazbatbam')
scanner.pos = 6
scanner.check_until(/bat/) # => "bazbat"
put_match_values(scanner)
# Basic match values:
# matched?: true
# matched_size: 3
# pre_match: "foobarbaz"
# matched : "bat"
# post_match: "bam"
# Captured match values:
# size: 1
# captures: []
# named_captures: {}
# values_at: ["bat", nil]
# []:
# [0]: "bat"
# [1]: nil
put_situation(scanner)
# Situation:
# pos: 6
# charpos: 6
# rest: "bazbatbam"
# rest_size: 9
Если сопоставление не удалось:
-
Очищает все значения совпадения.
-
Возвращает
nil.
scanner.check_until(/nope/) # => nil match_values_cleared?(scanner) # => true
Исходный код
static VALUE
strscan_concat(VALUE self, VALUE str)
{
struct strscanner *p;
GET_SCANNER(self, p);
StringValue(str);
rb_str_append(p->str, str);
return self;
} -
Добавляет заданную
more_stringк сохранённой строке. -
Возвращает
self. -
Не влияет на позиции или значения совпадения.
scanner = StringScanner.new('foo')
scanner.string # => "foo"
scanner.terminate
scanner.concat('barbaz') # => #<StringScanner 3/9 "foo" @ "barba...">
scanner.string # => "foobarbaz"
put_situation(scanner)
# Situation:
# pos: 3
# charpos: 3
# rest: "barbaz"
# rest_size: 6
Исходный код
static VALUE
strscan_eos_p(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
return EOS_P(p) ? Qtrue : Qfalse;
} Возвращает, находится ли позиция в конце сохранённой строки:
scanner = StringScanner.new('foobarbaz')
scanner.eos? # => false
pos = 3
scanner.eos? # => false
scanner.terminate
scanner.eos? # => true
Исходный код
static VALUE
strscan_exist_p(VALUE self, VALUE re)
{
return strscan_do_scan(self, re, 0, 0, 0);
} Попытка сопоставить заданный pattern где угодно (в любой позиции) в целевой подстроке; не изменяет позиции.
Если сопоставление успешно:
-
Возвращает смещение байтов: расстояние в байтах между текущей позицией и концом совпавшей подстроки.
-
Устанавливает все значения совпадения.
scanner = StringScanner.new('foobarbazbatbam')
scanner.pos = 6
scanner.exist?(/bat/) # => 6
put_match_values(scanner)
# Basic match values:
# matched?: true
# matched_size: 3
# pre_match: "foobarbaz"
# matched : "bat"
# post_match: "bam"
# Captured match values:
# size: 1
# captures: []
# named_captures: {}
# values_at: ["bat", nil]
# []:
# [0]: "bat"
# [1]: nil
put_situation(scanner)
# Situation:
# pos: 6
# charpos: 6
# rest: "bazbatbam"
# rest_size: 9
Если сопоставление не удалось:
-
Возвращает
nil. -
Очищает все значения совпадения.
scanner.exist?(/nope/) # => nil match_values_cleared?(scanner) # => true
Исходный код
static VALUE
strscan_fixed_anchor_p(VALUE self)
{
struct strscanner *p;
p = check_strscan(self);
return p->fixed_anchor_p ? Qtrue : Qfalse;
} Возвращает, установлено ли свойство фиксированной точки.
Исходный код
static VALUE
strscan_get_byte(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
CLEAR_MATCH_STATUS(p);
if (EOS_P(p))
return Qnil;
p->prev = p->curr;
p->curr++;
MATCHED(p);
adjust_registers_to_matched(p);
return extract_range(p,
adjust_register_position(p, p->regs.beg[0]),
adjust_register_position(p, p->regs.end[0]));
} call-seq: get_byte -> байт_как_символ или nil
Возвращает следующий байт, если он доступен:
-
Если позиция не находится в конце хранимой строки:
-
Возвращает следующий байт.
-
Увеличивает положение байта.
-
Корректирует положение символа.
scanner = StringScanner.new(HIRAGANA_TEXT) # => #<StringScanner 0/15 @ "\xE3\x81\x93\xE3\x82..."> scanner.string # => "こんにちは" [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\xE3", 1, 1] [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x81", 2, 2] [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x93", 3, 1] [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\xE3", 4, 2] [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x82", 5, 3] [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x93", 6, 2]
-
-
В противном случае возвращает
nil, и не изменяет позиции.scanner.terminate [scanner.get_byte, scanner.pos, scanner.charpos] # => [nil, 15, 5]
Исходный код
static VALUE
strscan_getch(VALUE self)
{
struct strscanner *p;
long len;
GET_SCANNER(self, p);
CLEAR_MATCH_STATUS(p);
if (EOS_P(p))
return Qnil;
len = rb_enc_mbclen(CURPTR(p), S_PEND(p), rb_enc_get(p->str));
len = minl(len, S_RESTLEN(p));
p->prev = p->curr;
p->curr += len;
MATCHED(p);
adjust_registers_to_matched(p);
return extract_range(p,
adjust_register_position(p, p->regs.beg[0]),
adjust_register_position(p, p->regs.end[0]));
} call-seq: getch -> символ или nil
Возвращает следующий (возможно, многобайтный) символ, если он доступен:
-
Если позиция находится в начале символа:
-
Возвращает символ.
-
Увеличивает положение символа на 1.
-
Увеличивает положение байта на размер символа (в байтах).
scanner = StringScanner.new(HIRAGANA_TEXT) scanner.string # => "こんにちは" [scanner.getch, scanner.pos, scanner.charpos] # => ["こ", 3, 1] [scanner.getch, scanner.pos, scanner.charpos] # => ["ん", 6, 2] [scanner.getch, scanner.pos, scanner.charpos] # => ["に", 9, 3] [scanner.getch, scanner.pos, scanner.charpos] # => ["ち", 12, 4] [scanner.getch, scanner.pos, scanner.charpos] # => ["は", 15, 5] [scanner.getch, scanner.pos, scanner.charpos] # => [nil, 15, 5]
-
-
Если позиция находится внутри многобайтного символа (то есть не в начале), ведет себя как
get_byte(возвращает 1-байтовый символ):scanner.pos = 1 [scanner.getch, scanner.pos, scanner.charpos] # => ["\x81", 2, 2] [scanner.getch, scanner.pos, scanner.charpos] # => ["\x93", 3, 1] [scanner.getch, scanner.pos, scanner.charpos] # => ["ん", 6, 2]
-
Если позиция находится в конце хранимой строки, возвращает
nilи не изменяет позиции:scanner.terminate [scanner.getch, scanner.pos, scanner.charpos] # => [nil, 15, 5]
Исходный код
static VALUE
strscan_inspect(VALUE self)
{
struct strscanner *p;
VALUE a, b;
p = check_strscan(self);
if (NIL_P(p->str)) {
a = rb_sprintf("#<%"PRIsVALUE" (uninitialized)>", rb_obj_class(self));
return a;
}
if (EOS_P(p)) {
a = rb_sprintf("#<%"PRIsVALUE" fin>", rb_obj_class(self));
return a;
}
if (p->curr == 0) {
b = inspect2(p);
a = rb_sprintf("#<%"PRIsVALUE" %ld/%ld @ %"PRIsVALUE">",
rb_obj_class(self),
p->curr, S_LEN(p),
b);
return a;
}
a = inspect1(p);
b = inspect2(p);
a = rb_sprintf("#<%"PRIsVALUE" %ld/%ld %"PRIsVALUE" @ %"PRIsVALUE">",
rb_obj_class(self),
p->curr, S_LEN(p),
a, b);
return a;
} Возвращает строковое представление self, которое может отображать:
-
Текущее положение.
-
Размер (в байтах) хранимой строки.
-
Подстроку, предшествующую текущему положению.
-
Подстроку, следующую за текущим положением (которая также является целевой подстрокой).
scanner = StringScanner.new("Fri Dec 12 1975 14:39")
scanner.pos = 11
scanner.inspect # => "#<StringScanner 11/21 \"...c 12 \" @ \"1975 ...\">"
Если в начале строки, элемент 4 выше (подстрока, следующая за текущим положением) опускается:
scanner.reset scanner.inspect # => "#<StringScanner 0/21 @ \"Fri D...\">"
Если в конце строки, все элементы выше опускаются:
scanner.terminate scanner.inspect # => "#<StringScanner fin>"
call-seq: pos = n -> n pointer = n -> n
Устанавливает позицию байта и позицию символа; возвращает n.
Не влияет на значения совпадения.
Для неотрицательного n, устанавливает позицию в n:
scanner = StringScanner.new(HIRAGANA_TEXT) scanner.string # => "こんにちは" scanner.pos = 3 # => 3 scanner.rest # => "んにちは" scanner.charpos # => 1
Для отрицательного n, считает с конца сохранённой строки:
scanner.pos = -9 # => -9 scanner.pos # => 6 scanner.rest # => "にちは" scanner.charpos # => 2
Исходный код
static VALUE
strscan_get_pos(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
return INT2FIX(p->curr);
} call-seq: pos -> byte_position
Возвращает целое число позиции байта, которая может отличаться от позиции символа:
scanner = StringScanner.new(HIRAGANA_TEXT) scanner.string # => "こんにちは" scanner.pos # => 0 scanner.getch # => "こ" # 3-byte character. scanner.charpos # => 1 scanner.pos # => 3
Исходный код
static VALUE
strscan_set_pos(VALUE self, VALUE v)
{
struct strscanner *p;
long i;
GET_SCANNER(self, p);
i = NUM2INT(v);
if (i < 0) i += S_LEN(p);
if (i < 0) rb_raise(rb_eRangeError, "index out of range");
if (i > S_LEN(p)) rb_raise(rb_eRangeError, "index out of range");
p->curr = i;
return LONG2NUM(i);
} call-seq: pos = n -> n pointer = n -> n
Устанавливает позицию байта и позицию символа; возвращает n.
Не влияет на значения совпадения.
Для неотрицательного n, устанавливает позицию в n:
scanner = StringScanner.new(HIRAGANA_TEXT) scanner.string # => "こんにちは" scanner.pos = 3 # => 3 scanner.rest # => "んにちは" scanner.charpos # => 1
Для отрицательного n, считает с конца сохранённой строки:
scanner.pos = -9 # => -9 scanner.pos # => 6 scanner.rest # => "にちは" scanner.charpos # => 2
Исходный код
static VALUE
strscan_post_match(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
if (! MATCHED_P(p)) return Qnil;
return extract_range(p,
adjust_register_position(p, p->regs.end[0]),
S_LEN(p));
} Возвращает подстроку, следующую за сопоставленной подстрокой с последней попытки сопоставления, если она была успешной, или nil в противном случае; см. Основные значения сопоставления:
scanner = StringScanner.new('foobarbaz')
scanner.post_match # => nil
scanner.pos = 3
scanner.match?(/bar/) # => 3
scanner.post_match # => "baz"
scanner.match?(/nope/) # => nil
scanner.post_match # => nil
Исходный код
static VALUE
strscan_pre_match(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
if (! MATCHED_P(p)) return Qnil;
return extract_range(p,
0,
adjust_register_position(p, p->regs.beg[0]));
} Возвращает подстроку, предшествующую сопоставленной подстроке с последней попытки сопоставления, если она была успешной, или nil в противном случае; см. Основные значения сопоставления:
scanner = StringScanner.new('foobarbaz')
scanner.pre_match # => nil
scanner.pos = 3
scanner.exist?(/baz/) # => 6
scanner.pre_match # => "foobar" # Substring of entire string, not just target string.
scanner.exist?(/nope/) # => nil
scanner.pre_match # => nil
Исходный код
static VALUE
strscan_reset(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
p->curr = 0;
CLEAR_MATCH_STATUS(p);
return self;
} Устанавливает позицию байта и позицию символа в ноль и очищает значения совпадений; возвращает self:
scanner = StringScanner.new('foobarbaz')
scanner.exist?(/bar/) # => 6
scanner.reset # => #<StringScanner 0/9 @ "fooba...">
put_situation(scanner)
# Situation:
# pos: 0
# charpos: 0
# rest: "foobarbaz"
# rest_size: 9
# => nil
match_values_cleared?(scanner) # => true
Исходный код
static VALUE
strscan_rest(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
if (EOS_P(p)) {
return str_new(p, "", 0);
}
return extract_range(p, p->curr, S_LEN(p));
} Возвращает остальную часть сохранённой строки (всё после текущей позиции), которая является целевой подстрокой:
scanner = StringScanner.new('foobarbaz')
scanner.rest # => "foobarbaz"
scanner.pos = 3
scanner.rest # => "barbaz"
scanner.terminate
scanner.rest # => ""
Исходный код
static VALUE
strscan_rest_size(VALUE self)
{
struct strscanner *p;
long i;
GET_SCANNER(self, p);
if (EOS_P(p)) {
return INT2FIX(0);
}
i = S_RESTLEN(p);
return INT2FIX(i);
} Возвращает размер (в байтах) rest сохранённой строки:
scanner = StringScanner.new('foobarbaz')
scanner.rest # => "foobarbaz"
scanner.rest_size # => 9
scanner.pos = 3
scanner.rest # => "barbaz"
scanner.rest_size # => 6
scanner.terminate
scanner.rest # => ""
scanner.rest_size # => 0
Исходный код
static VALUE
strscan_scan(VALUE self, VALUE re)
{
return strscan_do_scan(self, re, 1, 1, 1);
} call-seq: scan(pattern) -> substring or nil
Попытка сопоставить заданный pattern в начале целевой подстроки.
Если сопоставление успешно:
-
Возвращает сопоставленную подстроку.
-
Увеличивает позицию байта на
substring.bytesize, и может увеличить позицию символа. -
Устанавливает значения совпадений.
scanner = StringScanner.new(HIRAGANA_TEXT)
scanner.string # => "こんにちは"
scanner.pos = 6
scanner.scan(/に/) # => "に"
put_match_values(scanner)
# Basic match values:
# matched?: true
# matched_size: 3
# pre_match: "こん"
# matched : "に"
# post_match: "ちは"
# Captured match values:
# size: 1
# captures: []
# named_captures: {}
# values_at: ["に", nil]
# []:
# [0]: "に"
# [1]: nil
put_situation(scanner)
# Situation:
# pos: 9
# charpos: 3
# rest: "ちは"
# rest_size: 6
Если сопоставление не удалось:
-
Возвращает
nil. -
Не увеличивает позицию байта и символа.
-
Очищает значения совпадений.
scanner.scan(/nope/) # => nil match_values_cleared?(scanner) # => true
Исходный код
static VALUE
strscan_scan_byte(VALUE self)
{
struct strscanner *p;
VALUE byte;
GET_SCANNER(self, p);
CLEAR_MATCH_STATUS(p);
if (EOS_P(p))
return Qnil;
byte = INT2FIX((unsigned char)*CURPTR(p));
p->prev = p->curr;
p->curr++;
MATCHED(p);
adjust_registers_to_matched(p);
return byte;
} Сканирует один байт и возвращает его как целое число. Этот метод не чувствителен к многобайтовым символам. См. также: getch.
Исходный код
static VALUE
strscan_scan_until(VALUE self, VALUE re)
{
return strscan_do_scan(self, re, 1, 1, 0);
} call-seq: scan_until(pattern) -> substring or nil
Попытка сопоставления заданного pattern в любом месте (в любой позиции) целевой подстроки.
Если попытка сопоставления успешна:
-
Устанавливает значения совпадений.
-
Устанавливает позицию байта в конец сопоставленной подстроки; может скорректировать позицию символа.
-
Возвращает сопоставленную подстроку.
scanner = StringScanner.new(HIRAGANA_TEXT)
scanner.string # => "こんにちは"
scanner.pos = 6
scanner.scan_until(/ち/) # => "にち"
put_match_values(scanner)
# Basic match values:
# matched?: true
# matched_size: 3
# pre_match: "こんに"
# matched : "ち"
# post_match: "は"
# Captured match values:
# size: 1
# captures: []
# named_captures: {}
# values_at: ["ち", nil]
# []:
# [0]: "ち"
# [1]: nil
put_situation(scanner)
# Situation:
# pos: 12
# charpos: 4
# rest: "は"
# rest_size: 3
Если попытка сопоставления не удалась:
-
Очищает данные сопоставления.
-
Возвращает
nil. -
Не обновляет позиции.
scanner.scan_until(/nope/) # => nil match_values_cleared?(scanner) # => true
Исходный код
static VALUE
strscan_size(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
if (! MATCHED_P(p)) return Qnil;
return INT2FIX(p->regs.num_regs);
} Возвращает количество совпадений, если последняя попытка совпадения прошла успешно, nil в противном случае; см. Значения захваченных совпадений:
scanner = StringScanner.new('Fri Dec 12 1975 14:39')
scanner.size # => nil
pattern = /(?<wday>\w+) (?<month>\w+) (?<day>\d+) /
scanner.match?(pattern)
scanner.values_at(*0..scanner.size) # => ["Fri Dec 12 ", "Fri", "Dec", "12", nil]
scanner.size # => 4
scanner.match?(/nope/) # => nil
scanner.size # => nil
Исходный код
static VALUE
strscan_skip(VALUE self, VALUE re)
{
return strscan_do_scan(self, re, 1, 0, 1);
} call-seq: skip(pattern) match_size or nil
Пытается сопоставить указанный pattern в начале целевого подстроки;
Если совпадение успешно:
-
Увеличивает байтовый позицию на substring.bytesize, и может увеличить позицию символа.
-
Устанавливает значения совпадения.
-
Возвращает размер (в байтах) сопоставленной подстроки.
scanner = StringScanner.new(HIRAGANA_TEXT)
scanner.string # => "こんにちは"
scanner.pos = 6
scanner.skip(/に/) # => 3
put_match_values(scanner)
# Basic match values:
# matched?: true
# matched_size: 3
# pre_match: "こん"
# matched : "に"
# post_match: "ちは"
# Captured match values:
# size: 1
# captures: []
# named_captures: {}
# values_at: ["に", nil]
# []:
# [0]: "に"
# [1]: nil
put_situation(scanner)
# Situation:
# pos: 9
# charpos: 3
# rest: "ちは"
# rest_size: 6
scanner.skip(/nope/) # => nil
match_values_cleared?(scanner) # => true
Исходный код
static VALUE
strscan_skip_until(VALUE self, VALUE re)
{
return strscan_do_scan(self, re, 1, 0, 0);
} call-seq: skip_until(pattern) -> matched_substring_size or nil
Пытается сопоставить указанный pattern где угодно (в любой позиции) в целевой подстроке; не изменяет позиции.
Если попытка совпадения успешна:
-
Устанавливает значения совпадения.
-
Возвращает размер сопоставленной подстроки.
scanner = StringScanner.new(HIRAGANA_TEXT)
scanner.string # => "こんにちは"
scanner.pos = 6
scanner.skip_until(/ち/) # => 6
put_match_values(scanner)
# Basic match values:
# matched?: true
# matched_size: 3
# pre_match: "こんに"
# matched : "ち"
# post_match: "は"
# Captured match values:
# size: 1
# captures: []
# named_captures: {}
# values_at: ["ち", nil]
# []:
# [0]: "ち"
# [1]: nil
put_situation(scanner)
# Situation:
# pos: 12
# charpos: 4
# rest: "は"
# rest_size: 3
Если попытка совпадения не удалась:
-
Очищает значения совпадения.
-
Возвращает
nil.
scanner.skip_until(/nope/) # => nil match_values_cleared?(scanner) # => true
Исходный код
static VALUE
strscan_get_string(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
return p->str;
} Возвращает хранимую строку:
scanner = StringScanner.new('foobar')
scanner.string # => "foobar"
scanner.concat('baz')
scanner.string # => "foobarbaz"
Исходный код
static VALUE
strscan_set_string(VALUE self, VALUE str)
{
struct strscanner *p = check_strscan(self);
StringValue(str);
p->str = str;
p->curr = 0;
CLEAR_MATCH_STATUS(p);
return str;
} Заменяет хранимую строку на заданную other_string:
-
Устанавливает обе позиции в ноль.
-
Очищает значения совпадения.
-
Возвращает
other_string.
scanner = StringScanner.new('foobar')
scanner.scan(/foo/)
put_situation(scanner)
# Situation:
# pos: 3
# charpos: 3
# rest: "bar"
# rest_size: 3
match_values_cleared?(scanner) # => false
scanner.string = 'baz' # => "baz"
put_situation(scanner)
# Situation:
# pos: 0
# charpos: 0
# rest: "baz"
# rest_size: 3
match_values_cleared?(scanner) # => true
Исходный код
static VALUE
strscan_terminate(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
p->curr = S_LEN(p);
CLEAR_MATCH_STATUS(p);
return self;
} call-seq: terminate -> self
Устанавливает сканер на конец строки; возвращает self:
-
Устанавливает обе позиции на конец потока.
-
Очищает значения совпадения.
scanner = StringScanner.new(HIRAGANA_TEXT) scanner.string # => "こんにちは" scanner.scan_until(/に/) put_situation(scanner) # Situation: # pos: 9 # charpos: 3 # rest: "ちは" # rest_size: 6 match_values_cleared?(scanner) # => false scanner.terminate # => #<StringScanner fin> put_situation(scanner) # Situation: # pos: 15 # charpos: 5 # rest: "" # rest_size: 0 match_values_cleared?(scanner) # => true
Исходный код
static VALUE
strscan_unscan(VALUE self)
{
struct strscanner *p;
GET_SCANNER(self, p);
if (! MATCHED_P(p))
rb_raise(ScanError, "unscan failed: previous match record not exist");
p->curr = p->prev;
CLEAR_MATCH_STATUS(p);
return self;
} Устанавливает позицию на значение, предшествующее последней успешной попытке сопоставления:
scanner = StringScanner.new('foobarbaz')
scanner.scan(/foo/)
put_situation(scanner)
# Situation:
# pos: 3
# charpos: 3
# rest: "barbaz"
# rest_size: 6
scanner.unscan
# => #<StringScanner 0/9 @ "fooba...">
put_situation(scanner)
# Situation:
# pos: 0
# charpos: 0
# rest: "foobarbaz"
# rest_size: 9
Вызывает исключение, если значения совпадения очищены:
scanner.scan(/nope/) # => nil match_values_cleared?(scanner) # => true scanner.unscan # Raises StringScanner::Error.
Исходный код
static VALUE
strscan_values_at(int argc, VALUE *argv, VALUE self)
{
struct strscanner *p;
long i;
VALUE new_ary;
GET_SCANNER(self, p);
if (! MATCHED_P(p)) return Qnil;
new_ary = rb_ary_new2(argc);
for (i = 0; i<argc; i++) {
rb_ary_push(new_ary, strscan_aref(self, argv[i]));
}
return new_ary;
} Возвращает массив захваченных подстрок или nil при отсутствии таковых.
Для каждого specifier, возвращаемая подстрока [specifier]; см. [].
scanner = StringScanner.new('Fri Dec 12 1975 14:39')
pattern = /(?<wday>\w+) (?<month>\w+) (?<day>\d+) /
scanner.match?(pattern)
scanner.values_at(*0..3) # => ["Fri Dec 12 ", "Fri", "Dec", "12"]
scanner.values_at(*%i[wday month day]) # => ["Fri", "Dec", "12"]
Приватные методы экземпляра
Исходный код
static VALUE
strscan_init_copy(VALUE vself, VALUE vorig)
{
struct strscanner *self, *orig;
self = check_strscan(vself);
orig = check_strscan(vorig);
if (self != orig) {
self->flags = orig->flags;
self->str = orig->str;
self->prev = orig->prev;
self->curr = orig->curr;
if (rb_reg_region_copy(&self->regs, &orig->regs))
rb_memerror();
RB_GC_GUARD(vorig);
}
return vself;
} Возвращает поверхностную копию self; хранимая строка в копии — та же, что и в self.
Исходный код
static VALUE
strscan_scan_base10_integer(VALUE self)
{
char *ptr;
long len = 0;
struct strscanner *p;
GET_SCANNER(self, p);
CLEAR_MATCH_STATUS(p);
strscan_must_ascii_compat(p->str);
ptr = CURPTR(p);
long remaining_len = S_RESTLEN(p);
if (remaining_len <= 0) {
return Qnil;
}
if (ptr[len] == '-' || ptr[len] == '+') {
len++;
}
if (!rb_isdigit(ptr[len])) {
return Qnil;
}
MATCHED(p);
p->prev = p->curr;
while (len < remaining_len && rb_isdigit(ptr[len])) {
len++;
}
return strscan_parse_integer(p, 10, len);
} Исходный код
static VALUE
strscan_scan_base16_integer(VALUE self)
{
char *ptr;
long len = 0;
struct strscanner *p;
GET_SCANNER(self, p);
CLEAR_MATCH_STATUS(p);
strscan_must_ascii_compat(p->str);
ptr = CURPTR(p);
long remaining_len = S_RESTLEN(p);
if (remaining_len <= 0) {
return Qnil;
}
if (ptr[len] == '-' || ptr[len] == '+') {
len++;
}
if ((remaining_len >= (len + 2)) && ptr[len] == '0' && ptr[len + 1] == 'x') {
len += 2;
}
if (len >= remaining_len || !rb_isxdigit(ptr[len])) {
return Qnil;
}
MATCHED(p);
p->prev = p->curr;
while (len < remaining_len && rb_isxdigit(ptr[len])) {
len++;
}
return strscan_parse_integer(p, 16, len);
}
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.