Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: Ben Bacarisse Newsgroups: comp.programming Subject: Re: Coding while drunk and stoned take 2. (Yes, I know this is a cross post) Date: Thu, 27 Feb 2020 15:55:25 +0000 Organization: A noiseless patient Spider Lines: 112 Message-ID: <87y2souis2.fsf@bsb.me.uk> References: <0b8d1b58-3651-47ed-a2b8-63dc1d659c91@googlegroups.com> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Injection-Info: reader02.eternal-september.org; posting-host="c5b2f88804383f9a4f3ed96188f26610"; logging-data="8757"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+8feDMpkcZMvUJOerzfbOHfIW2L5gbehk=" Cancel-Lock: sha1:ujciOuQYONr4QoSyzA2e3XUej3g= sha1:0hf4yKQ9k1e/cxBbqRTjRxQSoh8= X-BSB-Auth: 1.22ee2c06569fbfb9b084.20200227155525GMT.87y2souis2.fsf@bsb.me.uk Xref: csiph.com comp.programming:10693 "Chad Altenburg, Ph.D." writes: > And here is the problem statement... > > Look for patterns like "zip" and "zap" in the string -- length-3, > starting with 'z' and ending with 'p'. Return a string where for all > such words, the middle letter is gone, so "zipXzap" yields "zpXzp". > > zipZap("zipXzap") → "zpXzp" > zipZap("zopzop") → "zpzp" > zipZap("zzzopzop") → "zzzpzp" > > > But the solution that I somehow managed to come up with when I was > drunk, stoned, depressed, and pissed off, is well, ugly... > > Here is the solution > > public String zipZap(String str) { > String newString = ""; > > if (str.length() < 3) { > return str; > } > > for (int i = 0; i < str.length() - 3; i++) { > if (str.charAt(i) == 'z' && str.charAt(i + 2) == 'p' ) { > newString = newString + "zp"; > i = i + 2; > } > else { > newString = newString + str.charAt(i); > } > > } > > for (int i = str.length() - 3; i < str.length(); i++ ) { > if (str.charAt(i) == 'z' && str.charAt(i + 2) == 'p' ) { > newString = newString + "zp"; > i = i + 2; > } > else { > newString = newString + str.charAt(i); > } > } > > return newString; > } > > The problem is that I have two loops. This is because I didn't know > how to attack the case when I have to search for a pattern at the > *end* of the string. If I use str.length(), I go out of bounds. So I > ended up using a second loop to handle the end of the string case. > > My gut feeling says this isn't right. But I have no idea how this > could be done in one loop. Here's a C solution. It's messy because the natural way to do string things in C is to pass an array to take the result. You then need to pass a size so the function does not write out-of-bounds. But to be useful the function should keep going and return the size that's needed even when there was no room this time: #include size_t zipzap(const char *src, char *dst, size_t n) { size_t i = 0; while (*src) { if (i < n) dst[i] = *src; i += 1; if (src[0] == 'z' && src[1] && src[2] == 'p') { if (i < n) dst[i] = 'p'; i += 1; src += 3; } else src += 1; } dst[i <= n ? i : n-1] = 0; return i + 1; } int main(int argc, char **argv) { char z[10]; for (int a = 1; a < argc; a++) { size_t required = zipzap(argv[a], z, sizeof z); printf("%s -> %s (%zu)\n", argv[a], z, required); } } The more "scripty" way -- allocating the result -- looks simpler: char *zipzap_str(const char *src) { char result[strlen(src) + 1], *dst = result; while (*src) { *dst++ = *src++; if (src[-1] == 'z' && src[0] && src[1] == 'p') { *dst++ = 'p'; src += 2; } } *dst++ = 0; char *rp = malloc(dst - result); return rp ? strcpy(rp, result) : 0; } -- Ben.