Skip to content

ast/topdown: add strings.split_n builtin#8361

Open
akios-ai wants to merge 2 commits intoopen-policy-agent:mainfrom
akios-ai:feat/strings-split-n
Open

ast/topdown: add strings.split_n builtin#8361
akios-ai wants to merge 2 commits intoopen-policy-agent:mainfrom
akios-ai:feat/strings-split-n

Conversation

@akios-ai
Copy link
Copy Markdown

Adds strings.split_n(string, delimiter, count) — wraps Go's strings.SplitN.

The existing split builtin always splits on every occurrence. This gives policies control over how many splits happen, which is useful when parsing structured strings where only the first (or first N) delimiters matter.

Semantics match Go's strings.SplitN:

  • n > 0: at most n substrings, last one gets the remainder
  • n == 0: nil
  • n < 0: all substrings (same as split)

Example:

strings.split_n("a.b.c.d", ".", 2)  # ["a", "b.c.d"]

Closes #8344


This change was developed with AI assistance.

Add strings.split_n(string, delimiter, count) builtin that splits a string
into at most count substrings. This wraps Go's strings.SplitN and provides
finer control than the existing split builtin.

Behavior matches Go's strings.SplitN semantics:
- n > 0: at most n substrings (last contains unsplit remainder)
- n == 0: returns nil (empty result)
- n < 0: all substrings (equivalent to split)

Resolves open-policy-agent#8344

Note: This change was developed with AI assistance.
Signed-off-by: aj <aj@mx4.ai>
@netlify
Copy link
Copy Markdown

netlify bot commented Feb 23, 2026

Deploy Preview for openpolicyagent ready!

Name Link
🔨 Latest commit be51629
🔍 Latest deploy log https://app.netlify.com/projects/openpolicyagent/deploys/699c67cbc743e80008456d66
😎 Deploy Preview https://deploy-preview-8361--openpolicyagent.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@anderseknert
Copy link
Copy Markdown
Member

anderseknert commented Feb 23, 2026

You'll need to run make generate for the failing build step to pass.

That aside, this does not seem to take the proposed handling of a negative number to mean split and limit from right-to-left into account. Was that simply missed?

Anyway, looks like a good start. Thanks!

Negative n now splits all occurrences, then returns the last |n|
elements from the right side. This matches the proposal in open-policy-agent#8344
where -2 on "a;b;c;d" returns ["c", "d"].

Also runs make generate to update capabilities.json and
builtin_metadata.json.

Note: This change was developed with AI assistance.
Signed-off-by: aj <aj@mx4.ai>
@akios-ai
Copy link
Copy Markdown
Author

Good catch on the negative number — I originally followed Go's SplitN semantics where negative means "all", but the right-to-left behavior from the issue makes more sense. Fixed: negative n now splits all then takes the last |n| from the right. Also ran make generate to pick up the generated files. Thanks for the review.

Copy link
Copy Markdown
Contributor

@johanfylling johanfylling left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi 👋


p := strings.split_n("a.b.c", ".", -1)
want_result:
- x: ["c"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have expected the right-to-left split to function exactly like the positive number variant, where the complete string is represented in the result components. I.e. if I were to do join the output on the same delimiter, I'd get back the original string: concat(".", split_n("1.2.3", ".", -1)) == "1.2.3"

E.g.

  • strings.split_n("a.b.c", ".", -1) = ["a.b.c"]
  • strings.split_n("a.b.c", ".", -2) = ["a.b", "c"]
  • strings.split_n("a.b.c", ".", -3) = ["a", "b", "c"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither version should keep any remaining parts of the string, but this should mean "split and return the first n results" from either left or right.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify: my comment here is about the discrepancy in behavior between positive and negative ns. If we're supposed to be dropping the "remainder" tail, e.g. strings.split_n("a.b.c.d", ".", 2) = ["a", "b"]; that's fine. It just should behave the same in both directions :)

@stale
Copy link
Copy Markdown

stale bot commented Mar 27, 2026

This pull request has been automatically marked as stale because it has not had any activity in the last 30 days.

@stale stale bot added the inactive label Mar 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add strings.split_n built-in function

3 participants