Skip to content

Commit d2186f9

Browse files
committed
Fixed incorrect handling of negative indices for find_first() and find_last().
1 parent 8d06ce8 commit d2186f9

File tree

2 files changed

+32
-10
lines changed

2 files changed

+32
-10
lines changed

jmespath/functions.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -313,25 +313,41 @@ def _func_keys(self, arg):
313313
{'type': 'string'},
314314
{'type': 'number', 'optional': True},
315315
{'type': 'number', 'optional': True})
316-
def _func_find_first(self, text, search, start = 0, end = -1):
317-
if len(search) == 0:
318-
return None
319-
if end == -1:
320-
end = len(text)
321-
pos = text.find(search, start, end)
322-
return pos if pos != -1 else None
316+
def _func_find_first(self, text, search, start = 0, end = None):
317+
return self._find_impl(
318+
text,
319+
search,
320+
lambda t, s: t.find(s),
321+
start,
322+
end
323+
)
323324

324325
@signature(
325326
{'type': 'string'},
326327
{'type': 'string'},
327328
{'type': 'number', 'optional': True},
328329
{'type': 'number', 'optional': True})
329-
def _func_find_last(self, text, search, start = 0, end = -1):
330+
def _func_find_last(self, text, search, start = 0, end = None):
331+
return self._find_impl(
332+
text,
333+
search,
334+
lambda t, s: t.rfind(s),
335+
start,
336+
end
337+
)
338+
339+
def _find_impl(self, text, search, func, start, end):
330340
if len(search) == 0:
331341
return None
332-
if end == -1:
342+
if end == None:
333343
end = len(text)
334-
pos = text[start:end].rfind(search)
344+
345+
pos = func(text[start:end], search)
346+
if start < 0:
347+
start = start + len(text)
348+
349+
# restrict resulting range to valid indices
350+
start = min(max(start, 0), len(text))
335351
return start + pos if pos != -1 else None
336352

337353
@signature(

tests/compliance/string_functions.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,26 @@
2626
{ "expression": "find_first(string, 'string')", "result": 8 },
2727
{ "expression": "find_first(string, 'string', `0`)", "result": 8 },
2828
{ "expression": "find_first(string, 'string', `0`, `14`)", "result": 8 },
29+
{ "expression": "find_first(string, 'string', `-6`)", "result": 8 },
2930
{ "expression": "find_first(string, 'string', `-99`, `100`)", "result": 8 },
3031
{ "expression": "find_first(string, 'string', `0`, `13`)", "result": null },
3132
{ "expression": "find_first(string, 'string', `8`)", "result": 8 },
33+
{ "expression": "find_first(string, 'string', `8`, `11`)", "result": null },
3234
{ "expression": "find_first(string, 'string', `9`)", "result": null },
3335
{ "expression": "find_first(string, 's')", "result": 0 },
3436
{ "expression": "find_first(string, 's', `1`)", "result": 8 },
3537
{ "expression": "find_first(string, '')", "result": null },
38+
{ "expression": "find_first('', '')", "result": null },
3639

3740
{ "expression": "find_last(string, 'string')", "result": 8 },
3841
{ "expression": "find_last(string, 'string', `8`)", "result": 8 },
3942
{ "expression": "find_last(string, 'string', `8`, `9`)", "result": null },
4043
{ "expression": "find_last(string, 'string', `9`)", "result": null },
4144
{ "expression": "find_last(string, 's', `1`)", "result": 8 },
45+
{ "expression": "find_last(string, 's', `-6`)", "result": 8 },
4246
{ "expression": "find_last(string, 's', `0`, `7`)", "result": 0 },
47+
{ "expression": "find_last(string, '')", "result": null },
48+
{ "expression": "find_last('', '')", "result": null },
4349

4450
{ "expression": "lower('STRING')", "result": "string" },
4551
{ "expression": "upper('string')", "result": "STRING" },

0 commit comments

Comments
 (0)