Split, slice, join and return "syntax" for str

Hi! I was thinking: perhaps it would be nice to be able to quicky split a string, do some slicing, and then obtaining the joined string back. Say we have the string: "docs.python.org", and we want to change "docs" to "wiki". Of course, there are a ton of simpler ways to solve this particular need, but perhaps str could have something like this: spam = "docs.python.org" eggs = "wiki." + spam['.'][1:] print(eggs) #wiki.python.org A quick implementation to get the idea and try it: class Mystr(str): def __getitem__(self, item): if isinstance(item, str): return Mystr_helper(self, item) else: return super().__getitem__(item) class Mystr_helper: def __init__(self, obj, sep): self.obj = obj self.sep = sep def __getitem__(self, item): return self.sep.join(self.obj.split(self.sep)[item]) What are your thoughts? Greetings from Argentina.

-1. I see no compelling reason to overload __getitem__ to provide a synonym for the split method. eggs = "wiki." + spam.split('.')[1:] Besides, you can already make such replacements more efficiently with eggs = spam.replace('docs', 'wiki') or, for more complex replacements, eggs = re.sub('^docs', 'wiki', spam) -- Clint

On Sun, Mar 04, 2018 at 01:44:20PM -0500, Clint Hepner wrote:
-1. I see no compelling reason to overload __getitem__ to provide a synonym for the split method.
eggs = "wiki." + spam.split('.')[1:]
Fair point. Neither do I. But your next comment:
Besides, you can already make such replacements more efficiently with
eggs = spam.replace('docs', 'wiki')
is not suitable, because it assumes that the substring "docs" appears only once in the string. In a more realistic example, you don't know what the string contains, only that it is delimited by dots and that you want to replace the n-th field (whatever it contains) with "wiki". -- Steve

Even if replace would be a better fit, I can see why doing those 3 operations in one row can be valuable. But, first, they are not common enough so that it's hard to do: spam = docs.python.org" eggs = 'wiki.' + '.'.join(spams.split('.')[1:]) It's not that long to type, and certainly is not happening in every single script you do. But let's say for the sake of argument you do a lot of cmd parsing, with a lot of split and join. Just make a helper: def rearrange(string, sep=None, start=None, stop=None, step=None): return sep.join(string.split(sep)[start:stop:step]) And then you can do: spam = docs.python.org" eggs = 'wiki.' + rearrange(spam, '.', 1) Simple, easy, no need to change Python. Le 04/03/2018 à 09:59, Andrés Delfino a écrit :

On Sun, Mar 04, 2018 at 12:11:16PM -0800, Michel Desmoulin wrote:
In a more realistic case, the delimiter is not necessarily a constant, nor will you always want to replace the first item. So you would be writing: delimiter.join( spam.split(delimiter)[:n-1] + ['wiki'] + spam.split(delimiter)[n+1:] ) Suddenly it's a lot less attractive to be typing out each time. It is a good candidate for a helper function: def replace_field(string, delimiter, position, new, start=0, end=None): fields = string[start:end].split(delimiter) fields[position] = new string = (string[:start] + delimiter.join(fields) + ('' if end is None else string[end:])) return string That's not the most efficient implementation, and it isn't thoroughly tested/debugged, but it ought to be good enough for casual use. Personally, if this were available as a string method I think I'd use this quite frequently, certainly more often than I use some other string methods like str.partition.
It's not that long to type, and certainly is not happening in every single script you do.
Speak for yourself :-) No, not literally every script. (If that were the requirement to be a string method, strings would have no methods.) But I think it is common enough that I'd be happy for it to be a string method. -- Steve

-1. I see no compelling reason to overload __getitem__ to provide a synonym for the split method. eggs = "wiki." + spam.split('.')[1:] Besides, you can already make such replacements more efficiently with eggs = spam.replace('docs', 'wiki') or, for more complex replacements, eggs = re.sub('^docs', 'wiki', spam) -- Clint

On Sun, Mar 04, 2018 at 01:44:20PM -0500, Clint Hepner wrote:
-1. I see no compelling reason to overload __getitem__ to provide a synonym for the split method.
eggs = "wiki." + spam.split('.')[1:]
Fair point. Neither do I. But your next comment:
Besides, you can already make such replacements more efficiently with
eggs = spam.replace('docs', 'wiki')
is not suitable, because it assumes that the substring "docs" appears only once in the string. In a more realistic example, you don't know what the string contains, only that it is delimited by dots and that you want to replace the n-th field (whatever it contains) with "wiki". -- Steve

Even if replace would be a better fit, I can see why doing those 3 operations in one row can be valuable. But, first, they are not common enough so that it's hard to do: spam = docs.python.org" eggs = 'wiki.' + '.'.join(spams.split('.')[1:]) It's not that long to type, and certainly is not happening in every single script you do. But let's say for the sake of argument you do a lot of cmd parsing, with a lot of split and join. Just make a helper: def rearrange(string, sep=None, start=None, stop=None, step=None): return sep.join(string.split(sep)[start:stop:step]) And then you can do: spam = docs.python.org" eggs = 'wiki.' + rearrange(spam, '.', 1) Simple, easy, no need to change Python. Le 04/03/2018 à 09:59, Andrés Delfino a écrit :

On Sun, Mar 04, 2018 at 12:11:16PM -0800, Michel Desmoulin wrote:
In a more realistic case, the delimiter is not necessarily a constant, nor will you always want to replace the first item. So you would be writing: delimiter.join( spam.split(delimiter)[:n-1] + ['wiki'] + spam.split(delimiter)[n+1:] ) Suddenly it's a lot less attractive to be typing out each time. It is a good candidate for a helper function: def replace_field(string, delimiter, position, new, start=0, end=None): fields = string[start:end].split(delimiter) fields[position] = new string = (string[:start] + delimiter.join(fields) + ('' if end is None else string[end:])) return string That's not the most efficient implementation, and it isn't thoroughly tested/debugged, but it ought to be good enough for casual use. Personally, if this were available as a string method I think I'd use this quite frequently, certainly more often than I use some other string methods like str.partition.
It's not that long to type, and certainly is not happening in every single script you do.
Speak for yourself :-) No, not literally every script. (If that were the requirement to be a string method, strings would have no methods.) But I think it is common enough that I'd be happy for it to be a string method. -- Steve
participants (4)
-
Andrés Delfino
-
Clint Hepner
-
Michel Desmoulin
-
Steven D'Aprano