feat: add wasm build targets, profile hooks, os_demo example, and restructure manual source
- Add `wasm`, `wasm-clean`, and `install-emscripten` phony targets to Makefile for WebAssembly cross-compilation - Insert `WREN_PROFILE_ENTER`/`WREN_PROFILE_EXIT` macros in `wren_vm.h` and `wren_vm.c` to support optional runtime profiling via `WREN_PROFILE_ENABLED` - Create `example/os_demo.wren` demonstrating Platform, Process, and conditional exit usage - Update `example/regex_demo.wren` to import `Match` and exercise Match object properties, groups, and `matchAll` - Remove static HTML manual pages (`base64.html`, `dns.html`, `json.html`) and replace with structured `manual_src/` directory containing Jinja2 templates, YAML metadata, and content pages - Expand `README.md` with build targets table, manual building instructions, source layout, and guide for adding new module documentation
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
{# retoor <retoor@molodetz.nl> #}
|
||||
{% extends 'page.html' %}
|
||||
|
||||
{% set page_title = "regex" %}
|
||||
{% set breadcrumb = [{"url": "api/index.html", "title": "API Reference"}, {"title": "regex"}] %}
|
||||
{% set prev_page = {"url": "api/base64.html", "title": "base64"} %}
|
||||
{% set next_page = {"url": "api/jinja.html", "title": "jinja"} %}
|
||||
|
||||
{% block article %}
|
||||
<h1>regex</h1>
|
||||
|
||||
<p>The <code>regex</code> module provides regular expression matching, replacement, and splitting using PCRE-compatible patterns.</p>
|
||||
|
||||
<pre><code>import "regex" for Regex, Match</code></pre>
|
||||
|
||||
<div class="toc">
|
||||
<h4>On This Page</h4>
|
||||
<ul>
|
||||
<li><a href="#regex-class">Regex Class</a></li>
|
||||
<li><a href="#match-class">Match Class</a></li>
|
||||
<li><a href="#pattern-syntax">Pattern Syntax</a></li>
|
||||
<li><a href="#examples">Examples</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2 id="regex-class">Regex Class</h2>
|
||||
|
||||
<div class="class-header">
|
||||
<h3>Regex</h3>
|
||||
<p>Regular expression pattern</p>
|
||||
</div>
|
||||
|
||||
<h3>Constructors</h3>
|
||||
|
||||
<div class="method-signature">
|
||||
<span class="method-name">Regex.new</span>(<span class="param">pattern</span>) → <span class="type">Regex</span>
|
||||
</div>
|
||||
<p>Creates a new regex from a pattern string.</p>
|
||||
<pre><code>var re = Regex.new("\\d+") // Match digits</code></pre>
|
||||
|
||||
<div class="method-signature">
|
||||
<span class="method-name">Regex.new</span>(<span class="param">pattern</span>, <span class="param">flags</span>) → <span class="type">Regex</span>
|
||||
</div>
|
||||
<p>Creates a regex with flags.</p>
|
||||
<ul class="param-list">
|
||||
<li><span class="param-name">pattern</span> <span class="param-type">(String)</span> - Regex pattern</li>
|
||||
<li><span class="param-name">flags</span> <span class="param-type">(String)</span> - Flags: "i" (case-insensitive), "m" (multiline), "s" (dotall)</li>
|
||||
</ul>
|
||||
<pre><code>var re = Regex.new("hello", "i") // Case-insensitive</code></pre>
|
||||
|
||||
<h3>Properties</h3>
|
||||
|
||||
<div class="method-signature">
|
||||
<span class="method-name">pattern</span> → <span class="type">String</span>
|
||||
</div>
|
||||
<p>The pattern string.</p>
|
||||
|
||||
<div class="method-signature">
|
||||
<span class="method-name">flags</span> → <span class="type">String</span>
|
||||
</div>
|
||||
<p>The flags string.</p>
|
||||
|
||||
<h3>Methods</h3>
|
||||
|
||||
<div class="method-signature">
|
||||
<span class="method-name">test</span>(<span class="param">string</span>) → <span class="type">Bool</span>
|
||||
</div>
|
||||
<p>Tests if the pattern matches anywhere in the string.</p>
|
||||
<pre><code>var re = Regex.new("\\d+")
|
||||
System.print(re.test("abc123")) // true
|
||||
System.print(re.test("abc")) // false</code></pre>
|
||||
|
||||
<div class="method-signature">
|
||||
<span class="method-name">match</span>(<span class="param">string</span>) → <span class="type">Match|null</span>
|
||||
</div>
|
||||
<p>Finds the first match in the string.</p>
|
||||
<pre><code>var re = Regex.new("(\\w+)@(\\w+\\.\\w+)")
|
||||
var m = re.match("email: alice@example.com")
|
||||
if (m != null) {
|
||||
System.print(m.text) // alice@example.com
|
||||
System.print(m.group(1)) // alice
|
||||
System.print(m.group(2)) // example.com
|
||||
}</code></pre>
|
||||
|
||||
<div class="method-signature">
|
||||
<span class="method-name">matchAll</span>(<span class="param">string</span>) → <span class="type">List</span>
|
||||
</div>
|
||||
<p>Finds all matches in the string.</p>
|
||||
<pre><code>var re = Regex.new("\\d+")
|
||||
var matches = re.matchAll("a1 b22 c333")
|
||||
for (m in matches) {
|
||||
System.print(m.text) // 1, 22, 333
|
||||
}</code></pre>
|
||||
|
||||
<div class="method-signature">
|
||||
<span class="method-name">replace</span>(<span class="param">string</span>, <span class="param">replacement</span>) → <span class="type">String</span>
|
||||
</div>
|
||||
<p>Replaces the first match with the replacement string.</p>
|
||||
<pre><code>var re = Regex.new("\\d+")
|
||||
System.print(re.replace("a1b2c3", "X")) // aXb2c3</code></pre>
|
||||
|
||||
<div class="method-signature">
|
||||
<span class="method-name">replaceAll</span>(<span class="param">string</span>, <span class="param">replacement</span>) → <span class="type">String</span>
|
||||
</div>
|
||||
<p>Replaces all matches with the replacement string.</p>
|
||||
<pre><code>var re = Regex.new("\\d+")
|
||||
System.print(re.replaceAll("a1b2c3", "X")) // aXbXcX</code></pre>
|
||||
|
||||
<div class="method-signature">
|
||||
<span class="method-name">split</span>(<span class="param">string</span>) → <span class="type">List</span>
|
||||
</div>
|
||||
<p>Splits the string by the pattern.</p>
|
||||
<pre><code>var re = Regex.new("[,;\\s]+")
|
||||
var parts = re.split("a, b; c d")
|
||||
System.print(parts) // [a, b, c, d]</code></pre>
|
||||
|
||||
<h2 id="match-class">Match Class</h2>
|
||||
|
||||
<div class="class-header">
|
||||
<h3>Match</h3>
|
||||
<p>Regex match result</p>
|
||||
</div>
|
||||
|
||||
<h3>Properties</h3>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Property</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>text</code></td>
|
||||
<td>String</td>
|
||||
<td>The matched text</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>start</code></td>
|
||||
<td>Num</td>
|
||||
<td>Start index in the original string</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>end</code></td>
|
||||
<td>Num</td>
|
||||
<td>End index in the original string</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>groups</code></td>
|
||||
<td>List</td>
|
||||
<td>List where index 0 is the entire match, index 1+ are capture groups</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3>Methods</h3>
|
||||
|
||||
<div class="method-signature">
|
||||
<span class="method-name">group</span>(<span class="param">index</span>) → <span class="type">String|null</span>
|
||||
</div>
|
||||
<p>Gets a captured group by index. Group 0 is the entire match.</p>
|
||||
<pre><code>var re = Regex.new("(\\w+)-(\\d+)")
|
||||
var m = re.match("item-42")
|
||||
System.print(m.group(0)) // item-42
|
||||
System.print(m.group(1)) // item
|
||||
System.print(m.group(2)) // 42</code></pre>
|
||||
|
||||
<div class="admonition note">
|
||||
<div class="admonition-title">Note</div>
|
||||
<p>The <code>groups</code> list uses 0-based indexing where <code>groups[0]</code> is the entire match (same as <code>text</code>), and <code>groups[1]</code>, <code>groups[2]</code>, etc. are the captured groups. This is consistent with <code>group(0)</code>, <code>group(1)</code>, etc.</p>
|
||||
</div>
|
||||
|
||||
<h2 id="pattern-syntax">Pattern Syntax</h2>
|
||||
|
||||
<h3>Character Classes</h3>
|
||||
<table>
|
||||
<tr><th>Pattern</th><th>Matches</th></tr>
|
||||
<tr><td><code>.</code></td><td>Any character (except newline)</td></tr>
|
||||
<tr><td><code>\d</code></td><td>Digit (0-9)</td></tr>
|
||||
<tr><td><code>\D</code></td><td>Non-digit</td></tr>
|
||||
<tr><td><code>\w</code></td><td>Word character (a-z, A-Z, 0-9, _)</td></tr>
|
||||
<tr><td><code>\W</code></td><td>Non-word character</td></tr>
|
||||
<tr><td><code>\s</code></td><td>Whitespace</td></tr>
|
||||
<tr><td><code>\S</code></td><td>Non-whitespace</td></tr>
|
||||
<tr><td><code>[abc]</code></td><td>Any of a, b, or c</td></tr>
|
||||
<tr><td><code>[^abc]</code></td><td>Not a, b, or c</td></tr>
|
||||
<tr><td><code>[a-z]</code></td><td>Range a through z</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>Quantifiers</h3>
|
||||
<table>
|
||||
<tr><th>Pattern</th><th>Matches</th></tr>
|
||||
<tr><td><code>*</code></td><td>0 or more</td></tr>
|
||||
<tr><td><code>+</code></td><td>1 or more</td></tr>
|
||||
<tr><td><code>?</code></td><td>0 or 1</td></tr>
|
||||
<tr><td><code>{n}</code></td><td>Exactly n times</td></tr>
|
||||
<tr><td><code>{n,}</code></td><td>n or more times</td></tr>
|
||||
<tr><td><code>{n,m}</code></td><td>Between n and m times</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>Anchors</h3>
|
||||
<table>
|
||||
<tr><th>Pattern</th><th>Matches</th></tr>
|
||||
<tr><td><code>^</code></td><td>Start of string/line</td></tr>
|
||||
<tr><td><code>$</code></td><td>End of string/line</td></tr>
|
||||
<tr><td><code>\b</code></td><td>Word boundary</td></tr>
|
||||
<tr><td><code>\B</code></td><td>Non-word boundary</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>Groups</h3>
|
||||
<table>
|
||||
<tr><th>Pattern</th><th>Description</th></tr>
|
||||
<tr><td><code>(abc)</code></td><td>Capturing group</td></tr>
|
||||
<tr><td><code>(?:abc)</code></td><td>Non-capturing group</td></tr>
|
||||
<tr><td><code>a|b</code></td><td>Alternation (a or b)</td></tr>
|
||||
</table>
|
||||
|
||||
<h2 id="examples">Examples</h2>
|
||||
|
||||
<h3>Email Validation</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var emailRe = Regex.new("^[\\w.+-]+@[\\w-]+\\.[\\w.-]+$")
|
||||
|
||||
var emails = ["alice@example.com", "invalid", "bob@test.org"]
|
||||
for (email in emails) {
|
||||
if (emailRe.test(email)) {
|
||||
System.print("%(email) is valid")
|
||||
} else {
|
||||
System.print("%(email) is invalid")
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<h3>Extracting Data</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var logRe = Regex.new("(\\d{4}-\\d{2}-\\d{2}) (\\w+): (.+)")
|
||||
var log = "2024-01-15 ERROR: Connection failed"
|
||||
|
||||
var m = logRe.match(log)
|
||||
if (m != null) {
|
||||
System.print("Date: %(m.group(1))") // 2024-01-15
|
||||
System.print("Level: %(m.group(2))") // ERROR
|
||||
System.print("Message: %(m.group(3))") // Connection failed
|
||||
}</code></pre>
|
||||
|
||||
<h3>Find and Replace</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var text = "Call 555-1234 or 555-5678"
|
||||
var phoneRe = Regex.new("\\d{3}-\\d{4}")
|
||||
|
||||
var redacted = phoneRe.replaceAll(text, "XXX-XXXX")
|
||||
System.print(redacted) // Call XXX-XXXX or XXX-XXXX</code></pre>
|
||||
|
||||
<h3>Parsing URLs</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var urlRe = Regex.new("(https?)://([^/]+)(/.*)?")
|
||||
var url = "https://example.com/path/to/page"
|
||||
|
||||
var m = urlRe.match(url)
|
||||
System.print("Scheme: %(m.group(1))") // https
|
||||
System.print("Host: %(m.group(2))") // example.com
|
||||
System.print("Path: %(m.group(3))") // /path/to/page</code></pre>
|
||||
|
||||
<div class="admonition note">
|
||||
<div class="admonition-title">Note</div>
|
||||
<p>Remember to escape backslashes in Wren strings. Use <code>\\d</code> instead of <code>\d</code>.</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user