{"id":32173459,"url":"https://github.com/shortishly/scran","last_synced_at":"2026-02-19T08:03:01.943Z","repository":{"id":179122224,"uuid":"662955218","full_name":"shortishly/scran","owner":"shortishly","description":"scran is a parser combinator library heavily influenced by nom","archived":false,"fork":false,"pushed_at":"2023-11-22T15:29:38.000Z","size":280,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-21T18:55:28.263Z","etag":null,"topics":["combinator","erlang","maybe","parser"],"latest_commit_sha":null,"homepage":"https://shortishly.github.io/scran/edoc","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shortishly.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-07-06T08:43:02.000Z","updated_at":"2024-06-20T20:53:10.000Z","dependencies_parsed_at":"2023-09-22T15:06:32.390Z","dependency_job_id":null,"html_url":"https://github.com/shortishly/scran","commit_stats":null,"previous_names":["shortishly/scran"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/shortishly/scran","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shortishly%2Fscran","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shortishly%2Fscran/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shortishly%2Fscran/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shortishly%2Fscran/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shortishly","download_url":"https://codeload.github.com/shortishly/scran/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shortishly%2Fscran/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29608152,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T06:47:36.664Z","status":"ssl_error","status_checked_at":"2026-02-19T06:45:47.551Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["combinator","erlang","maybe","parser"],"created_at":"2025-10-21T18:55:22.005Z","updated_at":"2026-02-19T08:03:01.937Z","avatar_url":"https://github.com/shortishly.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://shortishly.github.io/scran/cover/\"\u003e\n      \u003cimg alt=\"Test Coverage\" src=\"https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fshortishly.github.io%2Fscran%2Fcover%2Fcoverage.json\u0026query=%24.total\u0026suffix=%25\u0026style=flat-square\u0026label=Test%20Coverage\u0026color=green\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://shortishly.github.io/scran/edoc/\"\u003e\n      \u003cimg alt=\"edoc\" src=\"https://img.shields.io/badge/Documentation-edoc-green?style=flat-square\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://erlang.org/\"\u003e\n      \u003cimg alt=\"Erlang/OTP 25+\" src=\"https://img.shields.io/badge/Erlang%2FOTP-25%2B-green?style=flat-square\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003e\n      \u003cimg alt=\"Apache-2.0\" src=\"https://img.shields.io/github/license/shortishly/scran?style=flat-square\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n## What is scran?\n\nscran is a parser combinator library heavily influenced by\n[nom][nom-parser-combinators].\n\nUnlike nom, scran isn't primarily intended for binary parsing because\nwe already have [bit syntax expressions][erlang-bit-syntax] in\nErlang. However, it does have a small number of combinators for length\nencoded, or null terminated byte sequences (typically \"strings\"),\nbig/little integers with common bit sizes.\n\nInternally, scran uses the [maybe keyword, which is supported by OTP\n25+][maybe-expression].\n\n## Example\n\nEach parser returns a function that takes Unicode input, returning a\ntuple of the unmatched and matched input.\n\n```erlang\n1\u003e (scran_character_complete:tag(\"Hello\"))(\"Hello, World!\").\n{\", World!\",\"Hello\"}\n```\n\nWhere `\"Hello\"` has been matched by `tag(\"Hello\")` and `\", World!\"' is\nthe remaining input.\n\n```erlang\n2\u003e (scran_character_complete:tag(\"Hello\"))(\"hello, world!\"). \nnomatch\n```\n\nThe `tag(\"Hello\")` is case sensitive so there is `nomatch` for \"hello,\nworld!\".\n\n```erlang\n3\u003e (scran_character_complete:tag_no_case(\"Hello\"))(\"hello, world!\").\n{\", world!\",\"hello\"}\n4\u003e (scran_character_complete:tag_no_case(\"Hello\"))(\"hellO, wOrlD!\").\n{\", wOrlD!\",\"hellO\"}\n```\n\n`tag_no_case` can be used for case insensitive matching.\n\n## Character Complete\n\nThe `scran_character_complete` module has various parsers used match\ndifferent character classes or combinations.\n\n### alpha0\n\nThe `alpha0` parser will match zero or more alphabetic characters\nin the range of `[a-zA-Z]`.\n\n```erlang\n12\u003e (scran_character_complete:alpha0())(\"abc\").\n{[], \"abc\"}\n\n13\u003e (scran_character_complete:alpha0())(\"\").\n{[], []}\n\n14\u003e (scran_character_complete:alpha0())(\"abc123\").\n{\"123\", \"abc\"}\n\n15\u003e (scran_character_complete:alpha0())(\"123abc\").\n{\"123abc\", []}\n```\n\n### alpha1\n\nThe `alpha1` parser will match one or more alphabetic characters\nin the range of `[a-zA-Z]`.\n\n```erlang\n8\u003e (scran_character_complete:alpha1())(\"abc\").\n{[], \"abc\"}\n\n9\u003e (scran_character_complete:alpha1())(\"\").\nnomatch\n\n10\u003e (scran_character_complete:alpha1())(\"abc123\").\n{\"123\",\"abc\"}\n\n11\u003e (scran_character_complete:alpha1())(\"123abc\").\nnomatch\n```\n\n### alphanumeric0\n\nThe `alphanumeric0` parser will match zero or more alpha numeric\ncharacters in the range of `[a-zA-Z0-9]`.\n\n```erlang\n16\u003e (scran_character_complete:alphanumeric0())(\"abc\").\n{[], \"abc\"}\n\n17\u003e (scran_character_complete:alphanumeric0())(\"\").\n{[], []}\n\n18\u003e (scran_character_complete:alphanumeric0())(\"abc123\").\n{[], \"abc123\"}\n\n19\u003e (scran_character_complete:alphanumeric0())(\"123abc\").\n{[], \"123abc\"}\n\n20\u003e (scran_character_complete:alphanumeric0())(\"123abc!%^\").\n{\"!%^\",\"123abc\"}\n\n21\u003e (scran_character_complete:alphanumeric0())(\"!%^abc123\"). \n{\"!%^abc123\", []}\n```\n\n### alphanumeric1\n\nThe `alphanumeric1` parser will match one or more alpha numeric\ncharacters in the range of `[a-zA-Z0-9]`.\n\n```erlang\n24\u003e (scran_character_complete:alphanumeric1())(\"abc\").\n{[], \"abc\"}\n\n25\u003e (scran_character_complete:alphanumeric1())(\"\").\nnomatch\n\n26\u003e (scran_character_complete:alphanumeric1())(\"abc123\").\n{[], \"abc123\"}\n\n27\u003e (scran_character_complete:alphanumeric1())(\"123abc\").\n{[], \"123abc\"}\n\n28\u003e (scran_character_complete:alphanumeric1())(\"123abc!%^\").\n{\"!%^\", \"123abc\"}\n\n29\u003e (scran_character_complete:alphanumeric1())(\"!%^\").\nnomatch\n\n30\u003e (scran_character_complete:alphanumeric1())(\"!%^abc123\").\nnomatch\n```\n\n### digit0\n\nThe `digit0` parser will match zero or more numeric\ncharacters in the range of `[0-9]`.\n\n### digit1\n\nThe `digit1` parser will match one or more numeric\ncharacters in the range of `[0-9]`.\n\n### multispace0\n\nThe `multispace0` parser will match zero or more numeric\ncharacters in the range of `[\\\\s\\\\t\\\\n\\\\r]`.\n\n### multispace1\n\nThe `multispace1` parser will match one or more numeric\ncharacters in the range of `[\\\\s\\\\t\\\\n\\\\r]`.\n\n### none_of\n\nThe `none_of` parser will match if the next character of the input is\nnone of the supplied characters.\n\n### one_of\n\nThe `one_of` parser will match if the next character of the input is\none of the supplied characters.\n\n### re\n\nThe `re` parser will match if the input satisfies the supplied case\nsensitive regular expression.\n\n### re\\_no\\_case\n\nThe `re\\_no\\_case` parser will match if the input satisfies the supplied case\ninsensitive regular expression.\n\n### tag\n\nThe `tag` parser will match if the input matches the supplied case\nsensitive string.\n\n### tag\\_no\\_case\n\nThe `tag\\_no\\_case` parser will match if the input matches the supplied case\ninsensitive string.\n\n### take\n\nThe `take` parser will match if it can take the specified number of\ncharacters from the input.\n\n## Branches\n\nThe `scan_branch` module is used to specify different branches of\nparsing behaviour.\n\n### alt\n\nWith `scran_branch:alt/1` you can specify alternate parsers to\nuse. Each parser is tried in turn until `nomatch` is returned.\n\n```erlang\n1\u003e (scran_branch:alt([scran_character_complete:alpha1(),\n                      scran_character_complete:digit1()]))(\"abc123\").\n{\"123\",\"abc\"}\n\n2\u003e (scran_branch:alt([scran_character_complete:alpha1(),\n                      scran_character_complete:digit1()]))(\"123456\").\n{[],\"123456\"}\n\n3\u003e (scran_branch:alt([scran_character_complete:alpha1(),\n                      scran_character_complete:digit1()]))(\"123456abc\").\n{\"abc\",\"123456\"}\n\n4\u003e (scran_branch:alt([scran_character_complete:alpha1(),\n                      scran_character_complete:digit1()]))(\"!@£$\").\nnomatch\n```\n\n### permutation\n\n## scran_combinator\n\nThe `scan_combinator` module is used to specify parsers that are\ncombined into ones that can exhibit complex behaviours.\n\n### all_comsuming\n\nThis parser succeeds if all the input has been consumed by its child parser.\n\n### map_result\n\nThis parser maps a function on the result of a parser.\n\n### ignore_result\n\nThis parser ignores the result of a parser.\n\n### map_parser\n\nThis parser applies a parser over the result of another one.\n\n### opt\n\nAn optional parser, will return none if the option is not taken.\n\n### value\n\nThis parser returns the provided value if the child parser succeeds.\n\n### condition\n\nThis parser calls the supplied parser if the condition is met.\n\n### peek\n\nThis parser tries to apply its parser without consuming the input.\n\n### eof\n\nThis parser returns its input if it is at the end of input data.\n\n### is_not\n\nThis parser succeeds if the child parser returns an error.\n\n## Additional\n\nThe test cases are currently the best place to look at simple examples\nof the combinators. There is also a more complex example that is used\nto [parse part of the PostgreSQL grammar][github-com-pgsqlp].\n\n### coverage report\n\nCoverage report [is available here][scran-cover].\n\n### edoc\n\nedoc [is available here][scran-edoc].\n\n[erlang-bit-syntax]: https://www.erlang.org/doc/reference_manual/expressions.html#bit_syntax\n[github-com-pgsqlp]: https://github.com/shortishly/pgsqlp\n[maybe-expression]: https://www.erlang.org/doc/reference_manual/expressions.html#maybe\n[nom-parser-combinators]: https://github.com/rust-bakery/nom\n[scran-cover]: https://shortishly.github.io/scran/cover\n[scran-edoc]: https://shortishly.github.io/scran/edoc\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshortishly%2Fscran","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshortishly%2Fscran","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshortishly%2Fscran/lists"}