Basically, I have a string like "12345678" and need a list containing this information, but split into substrings of length 3. The problem is, that I need it to be right-aligned, so the output must be ['12', '345', '678'] and NOT ['123', '456', '78'].
How do I best achieve with few code lines and preferably without additional imports?
            Asked
            
        
        
            Active
            
        
            Viewed 471 times
        
    1
            
            
         
    
    
        kylieCatt
        
- 10,672
- 5
- 43
- 51
 
    
    
        Byte Commander
        
- 6,506
- 6
- 44
- 71
2 Answers
4
            
            
        It's easy enough to adapt the top answer from How do I split a list into equally-sized chunks?:
def chunks_rightaligned(l, n):
    orphan = len(l) % n
    if orphan:
        yield l[: orphan]         
    for i in range(orphan, len(l), n):
        yield l[i : i + n]
This yields a chunk of the remainder length first, then iterates over the indices in chunk-size steps starting from the orphan size rather than 0.
Demo:
>>> def chunks_rightaligned(l, n):
...     orphan = len(l) % n
...     if orphan:
...         yield l[: orphan]         
...     for i in range(orphan, len(l), n):
...         yield l[i : i + n]
... 
>>> list(chunks_rightaligned("12345678", 3))
['12', '345', '678']
>>> list(chunks_rightaligned("1234567", 3))
['1', '234', '567']
>>> list(chunks_rightaligned("123456", 3))
['123', '456']
 
    
    
        Martijn Pieters
        
- 1,048,767
- 296
- 4,058
- 3,343
1
            If you want to try regular expressions, you can use the re.split() function
>>> re.split(r"(...)(?=(?:\d\d\d)+$)","12345678")
['12', '345', '678']
>>> re.split(r"(...)(?=(?:\d\d\d)+$)","123")
['123']
EDIT
A better solution would be to use re.findall()
>>> re.findall(r"\d{1,3}(?=(?:\d{3})*$)", "12345")
['12', '345']
>>> re.findall(r"\d{1,3}(?=(?:\d{3})*$)", "123456")
['123', '456']
>>> re.findall(r"\d{1,3}(?=(?:\d{3})*$)", "1234567")
['1', '234', '567']
What it does?
- \d{1,3}Matches maximum of 3 characters, and minimum of 1 character.
- (?=(?:\d{3})*$)Positive look ahead. Ensures that the matched characters is followed by a multiple of 3 digits.- (?:\d{3})matches 3 digits.
 
You can use variables in the regex string to generate variable chunk of data.
Example
>>> $limit=4
>>> regex = r"\d{1,%d}(?=(?:\d{%d})*$)" %(limit,limit)
>>> re.findall(regex, "1234567")
['123', '4567']
>>> limit=3
>>> regex = r"\d{1,%d}(?=(?:\d{%d})*$)" %(limit,limit)
>>> re.findall(regex, "1234567")
['1', '234', '567']
 
    
    
        nu11p01n73R
        
- 26,397
- 3
- 39
- 52
- 
                    Would you please add a short explanation about the regex parts? I will probably prefer your answer, but I don't really understand the regex you use yet. – Byte Commander Jun 17 '15 at 16:15
- 
                    And it would be interesting how I could reuse this code for variable chunk lengths. – Byte Commander Jun 17 '15 at 16:23
- 
                    @ByteCommander I have added an edit and a small explanation. Hope it helps you. – nu11p01n73R Jun 17 '15 at 16:43