Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/imcflibs/strtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,44 @@ def pad_number(index, pad_length=2):
'0042'
"""
return str(index).zfill(pad_length)


def text_in_last_bracket_group(text):
"""Return the content of the last balanced square-bracket group.

Parameters
----------
text : str
The input string to search for the last balanced square-bracket group.

Returns
-------
str or None
The content of the last balanced square-bracket group, or None if no
such group exists.

Examples
--------
>>> text_in_last_bracket_group("foo[bar]baz")
'bar'
>>> text_in_last_bracket_group("foo[bar[baz]qux]")
'bar[baz]qux'
>>> text_in_last_bracket_group("foo[]bar")
''
>>> text_in_last_bracket_group("foobar")
None
"""
depth = 0
end = None

for index in range(len(text) - 1, -1, -1):
if text[index] == "]":
if end is None:
end = index
depth += 1
elif text[index] == "[":
depth -= 1
if depth == 0:
return text[index + 1 : end]

return None
62 changes: 57 additions & 5 deletions tests/test_strtools.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
"""Tests for `imcflibs.strtools`."""
# -*- coding: utf-8 -*-

import pytest
import os

from imcflibs.strtools import _is_string_like
from imcflibs.strtools import filename
from imcflibs.strtools import flatten
from imcflibs.strtools import strip_prefix
import pytest

from imcflibs.strtools import (
_is_string_like,
filename,
flatten,
strip_prefix,
text_in_last_bracket_group,
)


def test__is_string_like():
Expand Down Expand Up @@ -37,3 +41,51 @@ def test_strip_prefix():
"""Test `strip_prefix()`."""
assert strip_prefix("foobar", "foo") == "bar"
assert strip_prefix("foobar", "bar") == "foobar"


def test_text_in_last_bracket_group_basic():
"""Test `text_in_last_bracket_group()` with a single bracket group."""
assert text_in_last_bracket_group("foo[bar]baz") == "bar"


def test_text_in_last_bracket_group_multiple():
"""Test `text_in_last_bracket_group()` with multiple bracket groups."""
assert text_in_last_bracket_group("foo[bar]baz[qux]") == "qux"


def test_text_in_last_bracket_group_nested():
"""Test `text_in_last_bracket_group()` with nested bracket groups."""
assert text_in_last_bracket_group("foo[bar[baz]qux]") == "bar[baz]qux"


def test_text_in_last_bracket_group_empty():
"""Test `text_in_last_bracket_group()` with an empty bracket group."""
assert text_in_last_bracket_group("foo[]bar") == ""


def test_text_in_last_bracket_group_no_brackets():
"""Test `text_in_last_bracket_group()` with no bracket groups."""
assert text_in_last_bracket_group("foobar") is None


def test_text_in_last_bracket_group_empty_string():
"""Test `text_in_last_bracket_group()` with an empty string."""
assert text_in_last_bracket_group("") is None


def test_text_in_last_bracket_group_only_brackets():
"""Test `text_in_last_bracket_group()` with only brackets."""
assert text_in_last_bracket_group("[foo]") == "foo"


def test_text_in_last_bracket_group_deeply_nested():
"""Test `text_in_last_bracket_group()` with deeply nested brackets."""
assert text_in_last_bracket_group("foo[bar[baz[qux]]]") == "bar[baz[qux]]"


def test_multi_series_files():
"""Test `text_in_last_bracket_group()` with multiple series files."""
filename = "ChannelSD - DAPI 20x,SD - GFP 20x,SD - Cy3 20x,SD - Cy5 20x_Seq0002.nd2"
input = "%s [%s (series 1)]" % (filename, filename)
expected = "%s (series 1)" % filename
assert text_in_last_bracket_group(input) == expected
Loading