{"id":16611576,"url":"https://github.com/nvarner/recursive-regex","last_synced_at":"2025-03-10T19:43:10.358Z","repository":{"id":62269507,"uuid":"556633082","full_name":"nvarner/recursive-regex","owner":"nvarner","description":"Deserialize a string into a struct based on regular expression capture groups. Very like the recap crate, but regex deserialization here can be nested. (Mirror of a GitLab repo)","archived":false,"fork":false,"pushed_at":"2023-02-18T20:52:59.000Z","size":92,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-17T15:29:37.021Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://gitlab.com/nvarner/recursive-regex","language":"Rust","has_issues":false,"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/nvarner.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":"2022-10-24T08:08:07.000Z","updated_at":"2023-12-20T15:09:58.000Z","dependencies_parsed_at":"2024-11-20T13:16:47.761Z","dependency_job_id":null,"html_url":"https://github.com/nvarner/recursive-regex","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvarner%2Frecursive-regex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvarner%2Frecursive-regex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvarner%2Frecursive-regex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvarner%2Frecursive-regex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nvarner","download_url":"https://codeload.github.com/nvarner/recursive-regex/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242916521,"owners_count":20206368,"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":[],"created_at":"2024-10-12T01:38:25.828Z","updated_at":"2025-03-10T19:43:10.337Z","avatar_url":"https://github.com/nvarner.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Recursive Regex\n\nThe recursive regex algorithm is designed to be a simple, customizable\nparser for basic data files. It matches a regular expression to text as many\ntimes as possible, extracting data via capture groups. On each capture\ngroup, it may recurse with a new regular expression to further parse the\nresults.\n\nThe crate is designed to be used for \"parsing\" unstructured data or structured\ndata for which it's not worth writing a real parser. In particular, the\nmotivation is parsing homework questions, with question title, points,\ndescription, solution, etc. from a LaTeX file.\n\n## Basic example\n```rust\nuse recursive_regex::{RegexTree, from_regex_tree_and_str};\nuse serde::Deserialize;\n\n// Text we want to deseralize, possibly from a file\nlet text = r#\"\n1 2 456 true\n8 3 -54 false\n\"#;\n\n// Regex tree that breaks down each line into numbers and boolean, then breaks\n// down numbers into a vec. Regex trees can be explicitly constructed, like so,\n// or deserialized with the `deserialize-regex-tree` feature.\nlet regex_tree = RegexTree::root(r\"(?P\u003cnums\u003e[-\\d\\s]*) (?P\u003cyn\u003etrue|false)\")\n    .with_child(\"nums\", RegexTree::leaf(r\"-?\\d+\"))\n    .build();\n\n// Struct to deserialize each line into\n#[derive(Deserialize, Debug, PartialEq, Eq)]\nstruct Line {\n    nums: Vec\u003ci32\u003e,\n    yn: bool,\n}\n\nlet deserialized: Vec\u003cLine\u003e = from_regex_tree_and_str(\u0026regex_tree, \u0026text).unwrap();\nassert_eq!(deserialized, vec![\n    Line { nums: vec![1, 2, 456], yn: true },\n    Line { nums: vec![8, 3, -54], yn: false },\n]);\n```\n\n## Uncaptured\nWhen reading data from a large file, it may be important to verify that the\nentire file was actually parsed. This is possible via `get_uncaptured`.\n\nConsider the above example, but imagine having forgotten to allow for negative\nsigns. In a large enough file where negative signs are uncommon, it may be hard\nto notice their ommision. However, we can check to see what was not matched by\na top level regex.\n```rust\nuse recursive_regex::{RegexTree, get_uncaptured};\nuse serde::Deserialize;\n\nlet text = r#\"\n1 2 456 true\n8 3 -54 false\n\"#;\n\n// Note that we do not account for `-` in numbers. Some lines will not be\n// properly parsed.\nlet regex_tree = RegexTree::root(r\"(?P\u003cnums\u003e[\\d\\s]*) (?P\u003cyn\u003etrue|false)\")\n    .with_child(\"nums\", RegexTree::leaf(r\"\\d+\"))\n    .build();\n\n#[derive(Deserialize, Debug, PartialEq, Eq)]\nstruct Line {\n    nums: Vec\u003ci32\u003e,\n    yn: bool,\n}\n\nlet uncaptured: Vec\u003c\u0026str\u003e = get_uncaptured(\u0026regex_tree, \u0026text).collect();\n\n// We could inspect the output and notice the numbers, and negative sign, which\n// we had wanted to capture but did not\nassert_eq!(vec![\"\\n8 3 -\", \"\\n\"], uncaptured);\n```\n\n## Example use case\nThe following data file is being maintained by hand, but we want it in a\nmore structured format. We need to extract names and a list of the favorite\nnumbers associated with those names.\n```text\nLina's favorite number is 2\nSelah's favorite numbers are 3, 6, 8, and 12\nAili's favorite numbers are 1, 4, 10, and 13\nGemma's favorite numbers are 9, 10, 11, and 14\nGenoveva's favorite numbers are 2, 10, 11, 13, and 15\nEryk's favorite number is 6\nAlpheus's favorite numbers are 1, 6, 12, and 19\nSven's favorite numbers are 1 and 5\nAnnabella's favorite numbers are 2, 6, and 14\n```\n\nTo parse each line, we design the following regular expression\n```regex\n(?P\u003cname\u003e.*)'s favorite numbers? (?:is|are) (?P\u003cfavorite_nums\u003e.*)\n```\nand call it `line`. After running this on the file, we have a list of\nmatches. In each, the first capture group is the name, as desired. The\nsecond capture group looks like this:\n```text\n2\n12\n13\n9, 10, 11, and 14\n2, 10, 11, 13, and 15\n6\n1, 6, 12, and 19\n1 and 5\n2, 6, and 14\n```\n\nTo parse the numbers, we design the regular expression\n```regex\n\\d+\n```\nand call it `favorite_nums`. After running this on each of the second capture\ngroups from before, capture group zero will contain just one number. We\nreplace each of the second capture group entries with a list of numbers.\n\nWe now have structured data extracted from the file. In a JSON\nrepresentation and with some additional metadata, it looks like this:\n```json\n[\n    {\n        \"name\": \"Lina\",\n        \"favorite_nums\": [\"2\"]\n    },\n    {\n        \"name\": \"Selah\",\n        \"favorite_nums\": [\"3\", \"6\", \"8\", \"12\"]\n    },\n    {\n        \"name\": \"Aili\",\n        \"favorite_nums\": [\"1\", \"4\", \"10\", \"13\"]\n    },\n    {\n        \"name\": \"Gemma\",\n        \"favorite_nums\": [\"9\", \"10\", \"11\", \"14\"]\n    },\n    {\n        \"name\": \"Genoveva\",\n        \"favorite_nums\": [\"2\", \"10\", \"11\", \"13\", \"15\"]\n    },\n    {\n        \"name\": \"Eryk\",\n        \"favorite_nums\": [\"6\"]\n    },\n    {\n        \"name\": \"Alpheus\",\n        \"favorite_nums\": [\"1\", \"6\", \"12\", \"19\"]\n    },\n    {\n        \"name\": \"Sven\",\n        \"favorite_nums\": [\"1\", \"5\"]\n    },\n    {\n        \"name\": \"Annabella\",\n        \"favorite_nums\": [\"2\", \"6\", \"14\"]\n    }\n]\n```\n\nCorresponding code is available under `tests/favorite_numbers.rs`.\n\n## Features\n- `deserialize-regex-tree`: implements `Deserialize` for `RegexTree`. This\nallows users to provide a regex tree as a file and easily customize parsing at\nruntime.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnvarner%2Frecursive-regex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnvarner%2Frecursive-regex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnvarner%2Frecursive-regex/lists"}