[code] Split a long pathstring ~in half at the nearest '/'
-
[ code ] Split a long pathstring ~in half at the nearest '/'
Scenario:
(a) You have a very long absolute pathstring, and you want to display it in aUI.messagebox
, but don't want the dialog to be tremendously wide (or definately not wider than the screen.)
(b) You want the pathstring to look "correct", having the split on the nearest '/' near the middle of the string.Question: The following code is what I came up with (as I could not find any built-in Enumerable iterator that would do what I wanted.) Can anyone suggest a better or more consise (more readable,) way of doing this?
So you would have code that needs the method, like:
<span class="syntaxdefault">info </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxstring">"Couldn't load;\n\n"<br /></span><span class="syntaxdefault">info</span><span class="syntaxkeyword"><<</span><span class="syntaxdefault"> path_knife</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">pathstring</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">info</span><span class="syntaxkeyword"><<</span><span class="syntaxdefault"> </span><span class="syntaxstring">"\n\nAnswer this question for some action?"<br /></span><span class="syntaxdefault">choice </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> UI</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">messagebox</span><span class="syntaxkeyword">(</span><span class="syntaxdefault"> info</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> MB_YESNO</span><span class="syntaxkeyword">|</span><span class="syntaxdefault">96 </span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">choice </span><span class="syntaxkeyword">==</span><span class="syntaxdefault"> IDYES </span><span class="syntaxkeyword">?</span><span class="syntaxdefault"> do_sometask</span><span class="syntaxkeyword">()</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> do_othertask<br /></span>
And the
path_knife()
method:<span class="syntaxdefault">def path_knife</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">max</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">60</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> path </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> File</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">expand_path</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> if path</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length </span><span class="syntaxkeyword">></span><span class="syntaxdefault"> max<br /> </span><span class="syntaxcomment"># cut the file path into 2 lines<br /></span><span class="syntaxdefault"> spa </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault">0.54</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0.58</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0.62</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0.66</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0.71</span><span class="syntaxkeyword">]<br /></span><span class="syntaxdefault"> i</span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> for e in spa<br /> c </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">((</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length</span><span class="syntaxkeyword">)*</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">to_i<br /> x </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> while c </span><span class="syntaxkeyword">>=</span><span class="syntaxdefault"> 0<br /> </span><span class="syntaxkeyword">(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">c</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">]==</span><span class="syntaxstring">'/'</span><span class="syntaxkeyword">)?(</span><span class="syntaxdefault">break c</span><span class="syntaxkeyword">);((</span><span class="syntaxdefault">c</span><span class="syntaxkeyword">==</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">)?(</span><span class="syntaxdefault">break 0</span><span class="syntaxkeyword">);(</span><span class="syntaxdefault">c </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> c</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">))<br /></span><span class="syntaxdefault"> end </span><span class="syntaxcomment"># while<br /></span><span class="syntaxdefault"> </span><span class="syntaxkeyword">(</span><span class="syntaxdefault">x</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">to_f</span><span class="syntaxkeyword">/(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">to_f</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">1.0</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">>=</span><span class="syntaxdefault"> 0.45</span><span class="syntaxkeyword">)?(</span><span class="syntaxdefault">break x</span><span class="syntaxkeyword">);((</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">==</span><span class="syntaxdefault">spa</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">last</span><span class="syntaxkeyword">)?(</span><span class="syntaxdefault">break 0</span><span class="syntaxkeyword">);(</span><span class="syntaxdefault">next</span><span class="syntaxkeyword">))<br /></span><span class="syntaxdefault"> end </span><span class="syntaxcomment"># for<br /></span><span class="syntaxdefault"> </span><span class="syntaxcomment"># <br /></span><span class="syntaxdefault"> return </span><span class="syntaxstring">"#{path[0,i+1]} \n#{path[i+1,path.length-1]} "</span><span class="syntaxdefault"> if i</span><span class="syntaxkeyword">></span><span class="syntaxdefault">0<br /> return </span><span class="syntaxstring">"#{path} "</span><span class="syntaxdefault"> </span><span class="syntaxcomment"># just in case i is still 0<br /></span><span class="syntaxdefault"> else </span><span class="syntaxcomment"># leave it as one line<br /></span><span class="syntaxdefault"> return </span><span class="syntaxstring">"#{path} "<br /></span><span class="syntaxdefault"> end<br />end </span><span class="syntaxcomment"># def<br /></span><span class="syntaxdefault"> </span>
Here's an "unwound" edition of the same method, with annotation comments:
<span class="syntaxdefault">def path_knife</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">max</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">60</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> path </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> File</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">expand_path</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> if path</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length </span><span class="syntaxkeyword">></span><span class="syntaxdefault"> max<br /> </span><span class="syntaxcomment"># cut the file path into 2 lines<br /></span><span class="syntaxdefault"> <br /> </span><span class="syntaxcomment"># start point array of %<br /></span><span class="syntaxdefault"> spa </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault">0.54</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0.58</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0.62</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0.66</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0.71</span><span class="syntaxkeyword">]<br /></span><span class="syntaxdefault"> i</span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> for e in spa<br /> </span><span class="syntaxcomment"># Get a start index at e% into path.<br /></span><span class="syntaxdefault"> c </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">((</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length</span><span class="syntaxkeyword">)*</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">to_i<br /> <br /> </span><span class="syntaxcomment"># Iterate backwards from startpoint<br /></span><span class="syntaxdefault"> </span><span class="syntaxcomment"># until a '/' character is found, or<br /></span><span class="syntaxdefault"> </span><span class="syntaxcomment"># 0 is reached. Return result in x.<br /></span><span class="syntaxdefault"> x </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> while c </span><span class="syntaxkeyword">>=</span><span class="syntaxdefault"> 0<br /> if </span><span class="syntaxkeyword">(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">c</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">]==</span><span class="syntaxstring">'/'</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> break c<br /> else<br /> if c</span><span class="syntaxkeyword">==</span><span class="syntaxdefault">0<br /> break 0<br /> else<br /> c </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> c</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">1<br /> end<br /> end<br /> end </span><span class="syntaxcomment"># while<br /></span><span class="syntaxdefault"> <br /> </span><span class="syntaxcomment"># Test x to see if it's at least 45% of path;<br /></span><span class="syntaxdefault"> </span><span class="syntaxcomment"># if so, return result in i. If not, next.<br /></span><span class="syntaxdefault"> if x</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">to_f</span><span class="syntaxkeyword">/(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">to_f</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">1.0</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">>=</span><span class="syntaxdefault"> 0.45<br /> break x<br /> else<br /> break 0 if e</span><span class="syntaxkeyword">==</span><span class="syntaxdefault">spa</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">last<br /> end<br /> end </span><span class="syntaxcomment"># for<br /></span><span class="syntaxdefault"> </span><span class="syntaxcomment">#<br /></span><span class="syntaxdefault"> return </span><span class="syntaxstring">"#{path[0,i+1]} \n#{path[i+1,path.length-1]} "</span><span class="syntaxdefault"> if i</span><span class="syntaxkeyword">></span><span class="syntaxdefault">0<br /> return </span><span class="syntaxstring">"#{path} "</span><span class="syntaxdefault"> </span><span class="syntaxcomment"># just in case i is still 0<br /></span><span class="syntaxdefault"> else </span><span class="syntaxcomment"># leave it as one line<br /></span><span class="syntaxdefault"> return </span><span class="syntaxstring">"#{path} "<br /></span><span class="syntaxdefault"> end<br />end </span><span class="syntaxcomment"># def<br /></span><span class="syntaxdefault"> </span>
-
This is what a dialog using
path_knife()
looks like: -
def path_knife(path,max=60) path = File.expand_path(path) if path.length > max s = [] minlen = path.length path.gsub(/\//) {|piece| len = ($`.length - $'.length).abs if len < minlen then s = [ $`, $'] minlen = len end } return "#{s[0]}/\n#{s[1]}" else # leave it as one line return "#{path}" end end # def puts path_knife("C;/Program Files/Google/Google SketchUp 8/Plugins/test/error/NoMemoryError.rb")
-
How about:
def path_knife( path, max=60 ) fpath = File.expand_path(path) if( fpath.length > max ) rMax = fpath[0..max].reverse =~ /\// "#{fpath[0..(max - rMax)]}\n\t#{fpath[(max + 1 - rMax)...fpath.length]}" else "#{fpath}" end end
-
Looks good david, but it doesn't satisfy
@unknownuser said:
(b) You want the pathstring to look "correct", having the split on the nearest '/' near the middle of the string.
-
Isn't this a 'vicious' little Ruby exercise ??
At first blush, you think, "Oh simple string manipulation. No problem.." Then you actually try and code it.
It's a good one for a Ruby class, for sure.
@Todd: I had forgotten about the
$`` (prematch) and
$'` (postmatch) globals. That could simplify things, especially the string output at the end as you showed.@Dave: I had entertained the idea of
dup
'ing and reversing the path, and then using the standardString
class iterator.each_byte
and then stoping when a '/' was found between 45%..55% of the path length. I just didn't want to figure out that night, how to invert the reverse index. -
Well, I am using "max" to determine about where to split the path string. The assumption being that you know what string length looks OK in general. That should be a valid assumption for most legitimate path strings (at least, it would be for any system I've ever encountered). If strings get much longer than that, you'll need a slightly modified version to split into more than 2 lines. The code I provided could easily be modified to take fpath.length/2 to approximate the middle of the path string on the fly. Or, it could easily be modified to do splits into more than 2 lines.
-
Why not ?
<span class="syntaxdefault">def path_knife</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> max</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">60</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> return path if path</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length</span><span class="syntaxkeyword"><=</span><span class="syntaxdefault">max<br /> return path</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">0.</span><span class="syntaxkeyword">.(</span><span class="syntaxdefault">max</span><span class="syntaxkeyword">/</span><span class="syntaxdefault">2</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">to_i</span><span class="syntaxkeyword">]+</span><span class="syntaxstring">"..."</span><span class="syntaxkeyword">+</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">[-(</span><span class="syntaxdefault">max</span><span class="syntaxkeyword">/</span><span class="syntaxdefault">2</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">to_i</span><span class="syntaxkeyword">/</span><span class="syntaxdefault">2.</span><span class="syntaxkeyword">.-</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">]<br /></span><span class="syntaxdefault">end</span><span class="syntaxcomment">#def </span><span class="syntaxdefault"></span>
-
@tig said:
Why not ?
<span class="syntaxdefault">def path_knife</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> max</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">60</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> return path if path</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length</span><span class="syntaxkeyword"><=</span><span class="syntaxdefault">max<br /> return path</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">0.</span><span class="syntaxkeyword">.(</span><span class="syntaxdefault">max</span><span class="syntaxkeyword">/</span><span class="syntaxdefault">2</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">to_i</span><span class="syntaxkeyword">]+</span><span class="syntaxstring">"..."</span><span class="syntaxkeyword">+</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">[-(</span><span class="syntaxdefault">max</span><span class="syntaxkeyword">/</span><span class="syntaxdefault">2</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">to_i</span><span class="syntaxkeyword">/</span><span class="syntaxdefault">2.</span><span class="syntaxkeyword">.-</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">]<br /></span><span class="syntaxdefault">end</span><span class="syntaxcomment">#def </span><span class="syntaxdefault"></span>
That does not meet the specifications. It will divide folder names.
(The instructor grades you a C- for your effort.)EDIT: .. AND it does not return a two line string (or add padding to which is lacking in the API implementation of the
UI.messagbox
method.)EDIT2: Tested your suggestion and for the test path, it returns:
%(#008000)["C:/Program Files/Google/Google ...oMemoryError.rb"]
So, it also chops off part the filename at the end. -
Ok here's my current version:
<span class="syntaxdefault">def self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">path_knife</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">max</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">60</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> </span><span class="syntaxcomment"># make sure it's a Ruby path using '/'.<br /></span><span class="syntaxdefault"> path </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> File</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">expand_path</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> if path</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length </span><span class="syntaxkeyword">></span><span class="syntaxdefault"> max<br /> </span><span class="syntaxcomment"># cut the file path into 2 lines<br /></span><span class="syntaxdefault"> ok </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">((</span><span class="syntaxdefault">path</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">)*</span><span class="syntaxdefault">0.45</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">to_i<br /> cut </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> path</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">split</span><span class="syntaxkeyword">(</span><span class="syntaxcomment">//).each_with_index { |e,i|<br /></span><span class="syntaxdefault"> break i if</span><span class="syntaxkeyword">(</span><span class="syntaxdefault"> e</span><span class="syntaxkeyword">==</span><span class="syntaxstring">'/'</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">&&</span><span class="syntaxdefault"> i</span><span class="syntaxkeyword">>=</span><span class="syntaxdefault">ok </span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault"> cut </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> 0 unless cut</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(Integer)<br /></span><span class="syntaxdefault"> return </span><span class="syntaxstring">" #{path[0..cut]} \n #{path[(cut+1)..-1]} "</span><span class="syntaxdefault"> if cut</span><span class="syntaxkeyword">></span><span class="syntaxdefault">0<br /> end<br /> </span><span class="syntaxcomment"># otherwise, leave it as one line<br /></span><span class="syntaxdefault"> return </span><span class="syntaxstring">" #{path} "<br /></span><span class="syntaxdefault"> </span><span class="syntaxcomment">#<br /></span><span class="syntaxdefault">end </span><span class="syntaxcomment"># def<br /></span><span class="syntaxdefault"> </span>
**EDIT: Added test after iterator, to set
cut
to 0, if a string had no '/' characters (in which caseeach_with_index
just returns the array characters.)
Also removed frivolous line before iterator:cut = 0
EDIT 2:(2011-02-19) Simplified
path
substring references (line 11.)
Removed frivolouselse
clause (were lines 12 and 13.)**
Advertisement