std/regex.zc
Rama main · réplica de lectura del repositorio original.
include <tre.h>
@link("std/third-party/tre/tre_full.c")
import "./core.zc"
import "./string.zc"
import "./vec.zc"
import "./option.zc"
import "./mem.zc"
struct Match {
text: char*;
start: int;
len: int;
}
struct ZRegMatch {
rm_so: int;
rm_eo: int;
}
impl Match {
/// Compiles a regular expression pattern.
fn new(text: char*, start: int, len: int) -> Match {
return Match { text: text, start: start, len: len };
}
fn as_string(self) -> char* {
let s: char* = alloc_n<char>(self.len + 1);
memcpy(s, self.text + self.start, self.len);
s[self.len] = 0;
return s;
}
fn end(self) -> int {
return self.start + self.len;
}
}
struct Regex {
preg: void*;
pattern: char*;
flags: int;
}
impl Regex {
fn compile(pattern: char*) -> Regex {
return Regex::compile_with_flags(pattern, 1 | 2);
}
fn compile_with_flags(pattern: char*, flags: int) -> Regex {
let preg = alloc_bytes(1024);
let status: int = 0;
raw {
status = tre_regcomp((regex_t*)preg, pattern, flags);
}
if (status != 0) {
dealloc<void>(preg);
return Regex { preg: NULL, pattern: NULL, flags: flags };
}
return Regex { preg: preg, pattern: pattern, flags: flags };
}
fn is_valid(self) -> bool {
return self.preg != NULL;
}
/// Returns whether the pattern matches the text.
fn match(self, text: char*) -> bool {
if (self.preg == NULL) { return false; }
let res: bool = false;
raw {
res = (tre_regexec((regex_t*)self->preg, text, 0, 0, 0) == 0);
}
return res;
}
fn match_full(self, text: char*) -> bool {
return self.match(text);
}
fn match_at(self, text: char*, offset: int) -> bool {
if (self.preg == NULL) { return false; }
let len = strlen(text);
if (offset < 0 || offset > len) { return false; }
let res: bool = false;
raw {
res = (tre_regexec((regex_t*)self->preg, text + offset, 0, 0, 0) == 0);
}
return res;
}
/// Returns whether the pattern matches.
fn is_match(self, text: char*) -> bool {
return self.match(text);
}
/// Returns the first match, or `None`.
fn find(self, text: char*) -> Option<Match> {
if (self.preg == NULL) { return Option<Match>::None(); }
let pmatch: ZRegMatch[1];
let res: int = -1;
raw {
res = tre_regexec((regex_t*)self->preg, text, 1, (regmatch_t*)pmatch, 0);
}
if (res == 0) {
let start = pmatch[0].rm_so;
let end = pmatch[0].rm_eo;
if (start != -1) {
return Option<Match>::Some(Match::new(text, start, end - start));
}
}
return Option<Match>::None();
}
fn find_at(self, text: char*, start: int) -> Option<Match> {
let len = strlen(text);
if (start < 0 || start >= len) {
return Option<Match>::None();
}
return self.find(text + start);
}
/// Returns the number of matches.
fn count(self, text: char*) -> int {
if (self.preg == NULL) { return 0; }
let count = 0;
let pos = 0;
let t_len = strlen(text);
while (pos < t_len) {
let res: bool = false;
raw {
res = (tre_regexec((regex_t*)self->preg, text + pos, 0, 0, 0) == 0);
}
if (res) {
count = count + 1;
pos = pos + 1;
} else {
break;
}
}
return count;
}
/// Splits the text on matches.
fn split(self, text: char*) -> Vec<String> {
let parts = Vec<String>::new();
if (self.preg == NULL) {
parts.push(String::from(text));
return parts;
}
let t_len = strlen(text);
let last_pos = 0;
let pos = 0;
while (pos < t_len) {
let res: bool = false;
raw {
res = (tre_regexec((regex_t*)self->preg, text + pos, 0, 0, 0) == 0);
}
if (res) {
if (pos > last_pos) {
let before = text + last_pos;
let part_len = pos - last_pos;
let v = Vec<char>::new();
for (let i = 0; i < part_len; i = i + 1) {
v.push(before[i]);
}
v.push(0);
parts.push(String { vec: v });
}
last_pos = pos + 1;
pos = pos + 1;
} else {
pos = pos + 1;
}
}
if (last_pos < t_len) {
parts.push(String::from(text + last_pos));
}
return parts;
}
fn pattern(self) -> char* {
return self.pattern;
}
fn flags(self) -> int {
return self.flags;
}
fn is_valid_pattern(pattern: char*) -> bool {
let test_regex = Regex::compile(pattern);
let valid = test_regex.is_valid();
test_regex.destroy();
return valid;
}
fn destroy(self) {
if (self.preg != NULL) {
raw {
tre_regfree((regex_t*)self->preg);
}
dealloc<void>(self.preg);
}
}
}
fn regex_match(pattern: char*, text: char*) -> bool {
let re = Regex::compile(pattern);
let result = re.match(text);
re.destroy();
return result;
}
fn regex_find(pattern: char*, text: char*) -> Option<Match> {
let re = Regex::compile(pattern);
let result = re.find(text);
re.destroy();
return result;
}
fn regex_count(pattern: char*, text: char*) -> int {
let re = Regex::compile(pattern);
let count = re.count(text);
re.destroy();
return count;
}
fn regex_split(pattern: char*, text: char*) -> Vec<String> {
let re = Regex::compile(pattern);
let parts = re.split(text);
re.destroy();
return parts;
}