Skip to content
This repository was archived by the owner on Jan 9, 2023. It is now read-only.

Commit 66bef4e

Browse files
authored
Merge pull request #65 from tmadlener/fix-recursive-brace-expansion
Fix recursive brace expansion
2 parents b7f7479 + 1a7b20f commit 66bef4e

File tree

2 files changed

+55
-25
lines changed

2 files changed

+55
-25
lines changed

root_pandas/readwrite.py

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,57 @@
2727
NOEXPAND_PREFIX = 'noexpand:'
2828

2929

30-
def expand_braces(orig):
31-
r = r'.*?(\{.+[^\\]\})'
32-
p = re.compile(r)
33-
34-
s = orig[:]
35-
res = list()
36-
37-
m = p.search(s)
38-
if m is not None:
39-
sub = m.group(1)
40-
open_brace = s.find(sub)
41-
close_brace = open_brace + len(sub) - 1
42-
if sub.find(',') != -1:
43-
for pat in sub[1:-1].split(','):
44-
res.extend(expand_braces(s[:open_brace] + pat + s[close_brace+1:]))
45-
else:
46-
res.extend(expand_braces(s[:open_brace] + sub.replace('}', '\\}') + s[close_brace+1:]))
47-
else:
48-
res.append(s.replace('\\}', '}'))
30+
def _getitem(string, depth=0):
31+
"""
32+
Get an item from the string (where item is up to the next ',' or '}' or the
33+
end of the string)
34+
"""
35+
out = [""]
36+
while string:
37+
char = string[0]
38+
if depth and (char == ',' or char == '}'):
39+
return out, string
40+
if char == '{':
41+
groups_string = _getgroup(string[1:], depth+1)
42+
if groups_string is not None:
43+
groups, string = groups_string
44+
out = [a + g for a in out for g in groups]
45+
continue
46+
if char == '\\' and len(string) > 1:
47+
string, char = string[1:], char + string[1]
48+
49+
out, string = [a + char for a in out], string[1:]
50+
51+
return out, string
52+
53+
54+
def _getgroup(string, depth):
55+
"""
56+
Get a group from the string, where group is a list of all the comma
57+
separated substrings up to the next '}' char or the brace enclosed substring
58+
if there is no comma
59+
"""
60+
out, comma = [], False
61+
while string:
62+
items, string = _getitem(string, depth)
4963

50-
return list(set(res))
64+
if not string:
65+
break
66+
out += items
67+
68+
if string[0] == '}':
69+
if comma:
70+
return out, string[1:]
71+
return ['{' + a + '}' for a in out], string[1:]
72+
73+
if string[0] == ',':
74+
comma, string = True, string[1:]
75+
76+
return None
77+
78+
79+
def expand_braces(orig):
80+
return _getitem(orig, 0)[0]
5181

5282

5383
def get_nonscalar_columns(array):

tests/test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,10 @@ def test_brace_pattern_in_columns():
304304
assert_frame_equal(df[['var{03}', 'var2', 'var{04}']],
305305
reference_df[['var{03}', 'var2', 'var{04}']])
306306

307-
# # TODO Recursive expansions
308-
# df = read_root('tmp.root', columns=[r'var{0{2,3},1{1,3}}'])
309-
# assert set(df.columns) == {'var02', 'var03', 'var11', 'var13'}
310-
# assert_frame_equal(df[['var02', 'var03', 'var11', 'var13']],
311-
# reference_df[['var02', 'var03', 'var11', 'var13']])
307+
# Recursive expansions
308+
df = read_root('tmp.root', columns=[r'var{0{2,3},1{1,3}}'])
309+
assert set(df.columns) == {'var02', 'var03', 'var11', 'var13'}
310+
assert_frame_equal(df[['var02', 'var03', 'var11', 'var13']],
311+
reference_df[['var02', 'var03', 'var11', 'var13']])
312312

313313
os.remove('tmp.root')

0 commit comments

Comments
 (0)