Ctrl K
ComunidadGuías…

std/regex.zc

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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;
}