Path: csiph.com!fu-berlin.de!uni-berlin.de!not-for-mail From: boB Stepp Newsgroups: comp.lang.python Subject: Re: Extract the middle N chars of a string Date: Fri, 20 May 2016 23:00:39 -0500 Lines: 116 Message-ID: References: <573c8e97$0$1596$c3e8da3$5496439d@news.astraweb.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 X-Trace: news.uni-berlin.de 6QcEJsACV40mK1WKPSGsYA3GzrATkjyFSnDL21/YZbIg== Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.001 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'elif': 0.04; 'indices': 0.07; 'right;': 0.07; 'seemed': 0.07; '"""return': 0.09; 'expression:': 0.09; 'subject:string': 0.09; 'python': 0.10; 'index': 0.13; 'def': 0.13; 'wed,': 0.15; '(given': 0.16; '(when': 0.16; '2016': 0.16; 'conveys': 0.16; 'from:addr:robertvstepp': 0.16; 'from:name:bob stepp': 0.16; 'outputs': 0.16; 'received:io': 0.16; 'received:psf.io': 0.16; 'scratch': 0.16; 'similarly,': 0.16; "steve's": 0.16; 'thoughts?': 0.16; 'which,': 0.16; 'wrote:': 0.16; 'string': 0.17; 'duplicate': 0.18; 'odd': 0.18; 'form:': 0.22; 'function,': 0.22; 'own.': 0.22; 'am,': 0.23; 'seems': 0.23; 'this:': 0.23; 'header:In-Reply-To:1': 0.24; 'possibility': 0.27; 'right.': 0.27; 'message-id:@mail.gmail.com': 0.27; 'values': 0.28; 'attempting': 0.29; 'index,': 0.29; 'strings,': 0.29; 'character': 0.29; 'code:': 0.29; 'code': 0.30; 'post': 0.31; 'table': 0.32; 'getting': 0.33; 'problem': 0.33; 'usually': 0.33; "d'aprano": 0.33; 'errors,': 0.33; 'steven': 0.33; 'case,': 0.34; 'except': 0.34; 'list': 0.34; 'received:google.com': 0.35; 'expected': 0.35; 'but': 0.36; 'received:209.85': 0.36; 'cases': 0.36; 'to:addr:python-list': 0.36; 'subject:: ': 0.37; 'two': 0.37; 'desired': 0.37; 'received:209.85.213': 0.37; 'starting': 0.37; 'things': 0.38; 'doing': 0.38; 'received:209': 0.38; 'sure': 0.39; 'subject:the': 0.39; 'to:addr:python.org': 0.40; 'some': 0.40; 'your': 0.60; 'hope': 0.61; 'skip:u 10': 0.61; 'ending': 0.63; 'tutor': 0.66; 'led': 0.72; 'trial': 0.81; 'hand': 0.82; "'0123456789'": 0.84; '(2),': 0.84; 'cheating': 0.84; 'average': 0.93 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to; bh=VLTxfswzMdu6msXhedEChWCWYOLEHlf5oI5AVM2hrT8=; b=xMgqhxBcuptOmdC+F3voT+GceuBZKFE0doQUofpogWtcH/7djQBIW6pM2KUVNjeeiA /ffgF0G6N7dNsacTn7KqnUsFp/KtVl7V+39k7+OqwAqkZseXRI4LjJO8ZMtErxanwkf3 /VNOCoPuYMP9MgQhVYRhURMG2JWoncVaM/zkw+WPU2/Yu3Et1OwfZPcNTcgkUd6NbpuR L6/4wcH9b0Gwv1n/KQaDJ/e0rH+CN03poSxPVtYryhKMIf3yCv1s5v+E4RBiptB18YLd pAxk/5YFCVaS/0aKNwNzkQ15f6tyuCT5ISzi9MvuamAfx4VKF3haIzJXVJHlLpbdr226 QDXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to; bh=VLTxfswzMdu6msXhedEChWCWYOLEHlf5oI5AVM2hrT8=; b=QtSNFqKu7rGA0mQAX3KRFmrQlHBVD+zMrKY7Yj0veWVUsd+hK3cibCZeIxj9s8ZAHk oL7rMvdcZcwcaAvoTWmb1ssIjGBnubgnMFFamis2J9BbXZTG16cUFG2DneAguLiQIf8J Vm/M1F80JPU7hduEgGBzwp5bWzmVnsTxC3+UuM0oT05RrjLAXzv3xEKOafsDkpU7kXC1 AYg5Bm3Dx4BuVxUgV0uX7H6aGoMq9rpI/yiVv8vOcVJe21jmxzskcSZUK3yZFKnjk9cr wxCYcry1Pvc0d21hP7OryPStXjacokKlra//wylZ5GbVHynofw9Xt0S/x68iVeZqj7nk SCOw== X-Gm-Message-State: AOPr4FXqfqLICd0Zj/fPkE6pVaboGmQr+gzDGAubnz74uEEKrgKKk8kfNvswOuMVLRFFqrIUuAmXv9ZzDEmEtQ== X-Received: by 10.50.230.52 with SMTP id sv20mr5172863igc.80.1463803239218; Fri, 20 May 2016 21:00:39 -0700 (PDT) In-Reply-To: <573c8e97$0$1596$c3e8da3$5496439d@news.astraweb.com> X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Mailman-Original-Message-ID: X-Mailman-Original-References: <573c8e97$0$1596$c3e8da3$5496439d@news.astraweb.com> Xref: csiph.com comp.lang.python:108891 On Wed, May 18, 2016 at 10:47 AM, Steven D'Aprano wrote: > Getting the middle N seems like it ought to be easy: > > s[N//2:-N//2] > > but that is wrong. It's not even the right length! > > py> s = 'aardvark' > py> s[5//2:-5//2] > 'rdv' > > > So after spending a ridiculous amount of time on what seemed like it ought > to be a trivial function, and an embarrassingly large number of off-by-one > and off-by-I-don't-even errors, I eventually came up with this: > > def mid(string, n): > """Return middle n chars of string.""" > L = len(string) > if n <= 0: > return '' > elif n < L: > Lr = L % 2 > a, ar = divmod(L-n, 2) > b, br = divmod(L+n, 2) > a += Lr*ar > b += Lr*br > string = string[a:b] > return string As some of you know, I usually post on the Tutor list while attempting to learn Python as time permits. I had to try my hand at this problem as a learning opportunity. I hope you don't mind if I explain how I got to my solution and welcome your critiques, so I may improve. I chose to cheat my answers to the right; I did not think about the possibility of alternating the sides to allot the extra character (when needed) to average things out until I read everyone's answers after getting my own. I started considering two strings, s_even = '0123456789' and s_odd = '123456789', with trial values of n = 4 and n = 5 for how many characters to extract. This gave me the following four desired outputs to replicate: 1) s_even with n = 5. Desired output: '34567' (Cheating right.) => Slice s_even[3:8] 2) s_even with n = 4. Desired output: '3456' (Exact.) => Slice s_even[3:7] 3) s_odd with n = 5. Desired output: '34567' (Exact.) => Slice s_odd[2:7] 4) s_odd with n = 4. Desired output: '4567' (Cheating right.) => Slice s_odd[3:7] Starting to generalize to get the desired indices for each case: 1) (len(s_even)//2 - n//2):(len(s_even)//2 + n//2 + 1) 2) (len(s_even)//2 - n//2):(len(s_even)//2 + n//2) 3) (len(s_odd)//2 - n//2):(len(s_odd)//2 + n//2 + 1) 4) (len(s_odd)//2 + 1 - n//2):(len(s_odd)//2 + n//2 + 1) Looking at the starting index for each case, I had an extra 1 for case (4), which, in table form: n even n odd s_even 0 0 s_odd 1 0 To duplicate this I came up with the expression: (len(s)%2) * (1 - n%2) Similarly, for the ending slice index, all cases have an extra "+ 1" except for case (2), with the following table: n even n odd s_even 0 1 s_odd 1 1 And the expression: 1 - ((len(s) + 1)%2 * (n +1)%2) All this was scribbled onto scratch paper, so I hope I did not make any typos! This led me to the following code: py3: def mid(s, n): ... index0_offset = (len(s)%2) * (1 - n%2) ... index1_offset = 1 - ((len(s) + 1)%2) * ((n + 1)%2) ... index0 = len(s)//2 - n//2 + index0_offset ... index1 = len(s)//2 + n//2 + index1_offset ... return s[index0:index1] ... py3: s = '0123456789' py3: n = 5 py3: mid(s, n) '34567' py3: n = 4 py3: mid(s, n) '3456' py3: s = '123456789' py3: n = 5 py3: mid(s, n) '34567' py3: n = 4 py3: mid(s, n) '4567' py3: s = 'aardvark' py3: n = 5 py3: mid(s, n) 'rdvar' This also returns an empty string for values of n <= 0. As far as I can tell, my solution works (Given cheating right.). I ran it on all of Steve's examples, and I got what I expected given that I am consistently cheating right. But I am not sure my code adequately conveys an understanding of what I am doing to the casual reader. Thoughts? TIA! boB