Ha. But I should have tested the first function, right? Yes, that was also broken.<div><br></div><div><div>(define (string-trim s)</div><div>  (regexp-replace #px&quot;^\\s*(.*?)\\s*$&quot; s &quot;\\1&quot;))</div><div><br>
</div><div>... passes the test cases and is a lot faster than the broken version; it&#39;s now a little less than a 2x difference:</div><div><div><br></div><div>&gt; (test)</div><div>cpu time: 426 real time: 437 gc time: 22</div>
<div>cpu time: 231 real time: 230 gc time: 0</div><div>&gt; (test)</div><div>cpu time: 422 real time: 431 gc time: 21</div><div>cpu time: 231 real time: 231 gc time: 0</div><div>&gt; (test)</div><div>cpu time: 450 real time: 456 gc time: 21</div>
<div>cpu time: 237 real time: 261 gc time: 0</div></div><div><br></div><div><br></div><div><br></div><div><br></div><br><div class="gmail_quote">On Sat, Apr 2, 2011 at 6:23 PM, Jon Zeppieri <span dir="ltr">&lt;<a href="mailto:zeppieri@gmail.com">zeppieri@gmail.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><br><br><div class="gmail_quote"><div class="im">On Sat, Apr 2, 2011 at 6:06 PM, Robby Findler <span dir="ltr">&lt;<a href="mailto:robby@eecs.northwestern.edu" target="_blank">robby@eecs.northwestern.edu</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

(oh, and I meant to add the usual &quot;where are you test cases?!?!&quot;<br>
comment here, but forgot.)<br>
<font color="#888888"><br>
Robby<br></font></blockquote><div><br></div><div><br></div></div><div>Ugh, you&#39;re right. </div><div><br></div><div>My understanding is that the function is supposed to return a string equal to the input string with leading and trailing whitespace removed. But I wasn&#39;t the one who originally started the discussion; that was Richard Hixson. I just got curious, because he wanted to avoid using regexps for performance reasons (I think), and that made we wonder what the how large the difference was. </div>


<div><br></div><div>But back to the function... Yes, that&#39;s broken. (Also, it turns out that replacing #px with #rx may make the former function a lot faster, but it doesn&#39;t actually work, at all.)</div><div><br>

</div><div>In the second function, the end parameter to the second use of &#39;scan&#39; is wrong, of course, since first non-whitespace character in the string may also be the last.  So, changing the second string-trim function to:</div>

<div><br></div><div><div class="im"><div>(define (string-trim s)</div><div>  (define-syntax scan</div><div>    (syntax-rules ()</div><div>      ((_ s start end step)</div><div>       (for/first ((i (in-range start end step)) </div>
<div>                   #:when (not (char-whitespace? (string-ref s i))))</div>
<div>         i))))</div><div>  </div><div>  (let* ((len (string-length s))</div><div>         (last-index (sub1 len))</div><div>         (start (or (scan s 0 len 1) 0))</div></div><div>         (end (or (scan s last-index (sub1 start) -1) last-index)))</div>
<div class="im">
<div>    (substring s start (add1 end))))</div></div></div><div><br></div><div>... works on the the following test cases:</div><div><br></div><div><div>&gt; (string-trim &quot;&quot;)</div><div>&quot;&quot;</div><div>&gt; (string-trim &quot;a&quot;)</div>

<div>&quot;a&quot;</div><div>&gt; (string-trim &quot;ab&quot;)</div><div>&quot;ab&quot;</div><div>&gt; (string-trim &quot; ab&quot;)</div><div>&quot;ab&quot;</div><div>&gt; (string-trim &quot;   ab&quot;)</div><div>&quot;ab&quot;</div>

<div>&gt; (string-trim &quot;   ab   &quot;)</div><div>&quot;ab&quot;</div><div>&gt; (string-trim &quot;ab   &quot;)</div><div>&quot;ab&quot;</div><div><div>&gt; (string-trim &quot; s sdf d  &quot;)</div><div>&quot;s sdf d&quot;</div>

</div><div><br></div></div><div>... and the times aren&#39;t much altered.</div><div><br></div><font color="#888888"><div>-Jon</div></font><div><div></div><div class="h5"><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<font color="#888888">
</font><div><div></div><div><br>
On Sat, Apr 2, 2011 at 5:06 PM, Robby Findler<br>
&lt;<a href="mailto:robby@eecs.northwestern.edu" target="_blank">robby@eecs.northwestern.edu</a>&gt; wrote:<br>
&gt; I&#39;ve lost track of what the function is supposed to be doing, but your<br>
&gt; two functions don&#39;t agree on the input &quot;a &quot;, I don&#39;t think. I get<br>
&gt; this:<br>
&gt;<br>
&gt; (define (string-trim.1 s)<br>
&gt;  (regexp-replace #px&quot;^\\s*([^\\s]*)\\s*$&quot; s &quot;\\1&quot;))<br>
&gt;<br>
&gt; (define (string-trim.2 s)<br>
&gt;  (define-syntax scan<br>
&gt;    (syntax-rules ()<br>
&gt;      ((_ s start end step)<br>
&gt;       (for/first ((i (in-range start end step))<br>
&gt;                   #:when (not (char-whitespace? (string-ref s i))))<br>
&gt;         i))))<br>
&gt;<br>
&gt;  (let* ((len (string-length s))<br>
&gt;         (last-index (sub1 len))<br>
&gt;         (start (or (scan s 0 len 1) 0))<br>
&gt;         (end (or (scan s last-index start -1) last-index)))<br>
&gt;    (substring s start (add1 end))))<br>
&gt;<br>
&gt;&gt; (string-trim.2 &quot;a &quot;)<br>
&gt; &quot;a &quot;<br>
&gt;&gt; (string-trim.1 &quot;a &quot;)<br>
&gt; &quot;a&quot;<br>
&gt;<br>
&gt;<br>
&gt; On Sat, Apr 2, 2011 at 5:03 PM, Jon Zeppieri &lt;<a href="mailto:zeppieri@gmail.com" target="_blank">zeppieri@gmail.com</a>&gt; wrote:<br>
&gt;&gt; Actually #rx seems to be much faster than #px (in this case, at any rate),<br>
&gt;&gt; but it&#39;s still slower:<br>
&gt;&gt;&gt; (test)<br>
&gt;&gt; cpu time: 1162 real time: 1181 gc time: 40<br>
&gt;&gt; cpu time: 230 real time: 230 gc time: 0<br>
&gt;&gt;&gt; (test)<br>
&gt;&gt; cpu time: 1184 real time: 1198 gc time: 38<br>
&gt;&gt; cpu time: 258 real time: 259 gc time: 21<br>
&gt;&gt;&gt; (test)<br>
&gt;&gt; cpu time: 1220 real time: 1544 gc time: 40<br>
&gt;&gt; cpu time: 233 real time: 233 gc time: 0<br>
&gt;&gt;<br>
&gt;&gt; On Sat, Apr 2, 2011 at 5:56 PM, Jon Zeppieri &lt;<a href="mailto:zeppieri@gmail.com" target="_blank">zeppieri@gmail.com</a>&gt; wrote:<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; I was a bit surprised to find that the scanning-by-hand approach really is<br>
&gt;&gt;&gt; significantly faster than using regexps.<br>
&gt;&gt;&gt; Between these two functions:<br>
&gt;&gt;&gt; (define (string-trim s)<br>
&gt;&gt;&gt;   (regexp-replace #px&quot;^\\s*([^\\s]*)\\s*$&quot; s &quot;\\1&quot;))<br>
&gt;&gt;&gt; ... and ...<br>
&gt;&gt;&gt; (define (string-trim s)<br>
&gt;&gt;&gt;   (define-syntax scan<br>
&gt;&gt;&gt;     (syntax-rules ()<br>
&gt;&gt;&gt;       ((_ s start end step)<br>
&gt;&gt;&gt;        (for/first ((i (in-range start end step))<br>
&gt;&gt;&gt;                    #:when (not (char-whitespace? (string-ref s i))))<br>
&gt;&gt;&gt;          i))))<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;   (let* ((len (string-length s))<br>
&gt;&gt;&gt;          (last-index (sub1 len))<br>
&gt;&gt;&gt;          (start (or (scan s 0 len 1) 0))<br>
&gt;&gt;&gt;          (end (or (scan s last-index start -1) last-index)))<br>
&gt;&gt;&gt;     (substring s start (add1 end))))<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; ... the latter is much faster. On 100000 iterations, using the test<br>
&gt;&gt;&gt; string:<br>
&gt;&gt;&gt;  &quot;                                                      \n  \t foo bar<br>
&gt;&gt;&gt; baz\n                                    \r   &quot;<br>
&gt;&gt;&gt; as input, I&#39;m getting numbers like these (where the first time is for the<br>
&gt;&gt;&gt; regexp function and the second is for the hand-scanning function):<br>
&gt;&gt;&gt; &gt; (test)<br>
&gt;&gt;&gt; cpu time: 8003 real time: 8008 gc time: 0<br>
&gt;&gt;&gt; cpu time: 256 real time: 257 gc time: 22<br>
&gt;&gt;&gt; &gt; (test)<br>
&gt;&gt;&gt; cpu time: 8028 real time: 8025 gc time: 0<br>
&gt;&gt;&gt; cpu time: 255 real time: 255 gc time: 22<br>
&gt;&gt;&gt; &gt; (test)<br>
&gt;&gt;&gt; cpu time: 8418 real time: 8424 gc time: 0<br>
&gt;&gt;&gt; cpu time: 260 real time: 260 gc time: 22<br>
&gt;&gt;&gt; &gt; (test)<br>
&gt;&gt;&gt; cpu time: 8390 real time: 8401 gc time: 0<br>
&gt;&gt;&gt; cpu time: 252 real time: 253 gc time: 20<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; On Sat, Apr 2, 2011 at 5:20 PM, Richard Cleis &lt;<a href="mailto:rcleis@mac.com" target="_blank">rcleis@mac.com</a>&gt; wrote:<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; You can use an index to the string to find the location of your goal,<br>
&gt;&gt;&gt;&gt; then return the substring when you are done.<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; rac<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; On Apr 2, 2011, at 3:08 PM, Charles Hixson wrote:<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; &gt; This seems to be what I want the string-trim to do, but it seems that<br>
&gt;&gt;&gt;&gt; &gt; all the string copying would be expensive.  Is there a way to improve it by<br>
&gt;&gt;&gt;&gt; &gt; avoiding the string copying?<br>
&gt;&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt;&gt; &gt; My original inclination was to use a while loop with a test for<br>
&gt;&gt;&gt;&gt; &gt; non-whitespace, but that appears to not be something scheme supports.<br>
&gt;&gt;&gt;&gt; &gt;<br>
&gt;&gt;&gt;&gt; &gt; (define (string-trim s)<br>
&gt;&gt;&gt;&gt; &gt;    (let ( (l (string-length s) ) )<br>
&gt;&gt;&gt;&gt; &gt;      (cond<br>
&gt;&gt;&gt;&gt; &gt;        [ (= l 0) #f]<br>
&gt;&gt;&gt;&gt; &gt;        [ (char-whitespace? (string-ref s (- l 1) ) )    (string-trim<br>
&gt;&gt;&gt;&gt; &gt; (substring s 0 (- l 1) ) ) ]<br>
&gt;&gt;&gt;&gt; &gt;        [else s]) ) )<br>
&gt;&gt;&gt;&gt; &gt; _________________________________________________<br>
&gt;&gt;&gt;&gt; &gt; For list-related administrative tasks:<br>
&gt;&gt;&gt;&gt; &gt; <a href="http://lists.racket-lang.org/listinfo/users" target="_blank">http://lists.racket-lang.org/listinfo/users</a><br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; _________________________________________________<br>
&gt;&gt;&gt;&gt;  For list-related administrative tasks:<br>
&gt;&gt;&gt;&gt;  <a href="http://lists.racket-lang.org/listinfo/users" target="_blank">http://lists.racket-lang.org/listinfo/users</a><br>
&gt;&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; _________________________________________________<br>
&gt;&gt;  For list-related administrative tasks:<br>
&gt;&gt;  <a href="http://lists.racket-lang.org/listinfo/users" target="_blank">http://lists.racket-lang.org/listinfo/users</a><br>
&gt;&gt;<br>
&gt;<br>
</div></div></blockquote></div></div></div><br>
</blockquote></div><br></div>