{"id":20975978,"url":"https://github.com/banyc/peg","last_synced_at":"2025-07-02T00:09:14.602Z","repository":{"id":153244845,"uuid":"628041601","full_name":"Banyc/peg","owner":"Banyc","description":"`grep` but with PEG patterns. Define grammars (e.g. `digit`), functions for matching. No more regex syntax!","archived":false,"fork":false,"pushed_at":"2023-04-18T11:47:44.000Z","size":47,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-13T09:18:54.571Z","etag":null,"topics":["grep","parsing-expression-grammars","peg"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Banyc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-14T19:16:48.000Z","updated_at":"2023-04-18T09:20:16.000Z","dependencies_parsed_at":null,"dependency_job_id":"30fc2fae-2560-405b-8099-1bcf18420efd","html_url":"https://github.com/Banyc/peg","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Banyc/peg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Banyc%2Fpeg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Banyc%2Fpeg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Banyc%2Fpeg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Banyc%2Fpeg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Banyc","download_url":"https://codeload.github.com/Banyc/peg/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Banyc%2Fpeg/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263052432,"owners_count":23406106,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["grep","parsing-expression-grammars","peg"],"created_at":"2024-11-19T04:48:24.034Z","updated_at":"2025-07-02T00:09:14.550Z","avatar_url":"https://github.com/Banyc.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PEG\n\n## `peggrep`\n\nExample file `demo_file`:\n\n```text\nTHIS LINE IS THE 1ST UPPER CASE LINE IN THIS FILE.\nthis line is the 1st lower case line in this file.\nThis Line Has All Its First Character Of The Word With Upper Case.\n\nTwo lines above this line is empty.\nAnd this is the last line.\n```\n\n### Match literals\n\n```bash\n$ peggrep \"'this'\" demo_file\nthis line is the 1st lower case line in this file.\nTwo lines above this line is empty.\nAnd this is the last line.\n```\n\n- `'this'`: match the literal string \"this\"\n\n### Match `this.*empty`\n\n```bash\n$ peggrep \"'this' (!'empty' .)* 'empty'\" demo_file\nTwo lines above this line is empty.\n```\n\n- `!'empty'`:\n  - def: true if the current position is not followed by \"empty\"\n  - `!` does not consume any characters\n- `.`: consume one character unconditionally\n- `(!'empty' .)*`:\n  - def: match any number of characters that are not followed by \"empty\"\n  - when the position is at the `e` of \"empty\", the `(!'empty' .)*` exits\n  - why not just `.* 'empty'`:\n    - `*` is greedy in PEG\n    - `.*` will consume \"empty\" without exiting, so `'empty'` has no chance to match\n- The final `'empty'`: match and consume the \"empty\"\n\nTo make life easier, we can make `(!'empty' .)* 'empty'` into a function:\n\n1. Write a grammar file:\n   ```py\n   // grammar.peg\n   until[str] \u003c- (!str .)* str\n               ;\n   ```\n1. Run with the grammar file:\n   ```bash\n   $ peggrep -g grammar.peg \"'this' until['empty']\" demo_file\n   Two lines above this line is empty.\n   ```\n\n### Match digits\n\nSteps:\n\n1. Write a grammar file:\n   ```py\n   // grammar.peg\n   digit \u003c- '0' / '1' / '2' / '3' / '4' / '5' / '6' / '7' / '8' / '9'\n          ;\n   ```\n1. Run with the grammar file:\n   ```bash\n   $ peggrep -g grammar.peg \"digit+\" demo_file\n   THIS LINE IS THE 1ST UPPER CASE LINE IN THIS FILE.\n   this line is the 1st lower case line in this file.\n   ```\n\n### Grammar file from environment variable\n\nWe don't want to write a grammar file every time we want to use it. We can use the environment variable `PEGGREP_GRAMMAR` to specify the grammar file:\n\n```bash\n$ export PEGGREP_GRAMMAR=\"/absolute/path/to/grammar.peg\"\n$ peggrep \"'this' until['empty']\" demo_file\nTwo lines above this line is empty.\n```\n\n### Match all private functions\n\nSteps:\n\n1. Write a grammar file:\n   ```py\n   // grammar.peg\n   space \u003c- ' ' / '\\t' / '\\r' / '\\n'\n          ;\n   _     \u003c- space*\n          ;\n   ```\n1. Run:\n   ```bash\n   $ export PEGGREP_GRAMMAR=\"/absolute/path/to/grammar.peg\"\n   $ peggrep -^ \"_ !'pub' 'fn'\" src/*.rs\n   ```\n   - `-^`: match at the start of a line\n   - `_`:\n     - predefined in the grammar file\n     - to match any number of spaces\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbanyc%2Fpeg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbanyc%2Fpeg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbanyc%2Fpeg/lists"}