Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/Additional+string+functions?V=84
QUERY_STRINGV=84
CONTENT_TYPE
DOCUMENT_URI/revision/Additional+string+functions
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.70.130.239
REMOTE_PORT43980
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR18.191.236.174
HTTP_CF_RAY87f5b21c1cb48726-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_CF_CONNECTING_IP18.191.236.174
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit {Additional string functions} This\ page\ describes\ various\ string\ processing\ that\ exist\ beside\ the\ standard\ commands\n\n<<TOC>>\n\n**\ List\ **\n\n%|name|description|%\n&|\[texutil%|%adjust%|%\]||&\n&|\[texutil%|%tcllib::textutil::adjust%|%\]||&\n&|\[texutil%|%tcllib::textutil::readPatterns%|%\]||&\n&|\[texutil%|%tcllib::textutil::listPredefined%|%\]||&\n&|\[texutil%|%tcllib::textutil::getPredefined%|%\]||&\n&|\[texutil%|%tcllib::textutil::indent%|%\]||&\n&|\[texutil%|%tcllib::textutil::undent%|%\]||&\n&|\[texutil%|%tcllib::textutil::splitn%|%\]||&\n&|\[texutil%|%tcllib::textutil::splitx%|%\]||&\n&|\[texutil%|%tcllib::textutil::tabify%|%\]||&\n&|\[texutil%|%tcllib::textutil::tabify2%|%\]||&\n&|\[texutil%|%tcllib::textutil::trim%|%\]||&\n&|\[texutil%|%tcllib::textutil::trimleft%|%\]||&\n&|\[texutil%|%tcllib::textutil::trimrigth%|%\]||&\n&|\[texutil%|%tcllib::textutil::trimprefix%|%\]||&\n&|\[texutil%|%tcllib::textutil::trimEmptyHeading%|%\]||&\n&|\[texutil%|%tcllib::textutil::untabify%|%\]||&\n&|\[texutil%|%tcllib::textutil::untabify2%|%\]||&\n&|\[texutil%|%tcllib::textutil::repeat%|%\]||&\n&|\[texutil%|%tcllib::textutil::blank%|%\]||&\n&|\[texutil%|%tcllib::textutil::chop%|%\]||&\n&|\[texutil%|%tcllib::textutil::tail%|%\]||&\n&|\[texutil%|%tcllib::textutil::cap%|%\]||&\n&|\[texutil%|%tcllib::textutil::uncap%|%\]||&\n&|\[texutil%|%tcllib::textutil::longestCommonPrefixList%|%\]||&\n&|\[texutil%|%tcllib::textutil::longestCommonPrefix%|%\]||&\n&|\[ycl%|%delimit%|%\]|split\ (partition)\ a\ string\ into\ substrings\ using\ any\ combination\ of\ string,\ match,\ or\ regular\ expressions,\ returning\ both\ the\ substrings\ and\ the\ delimiters.|&\n&|\[ycl%|%shortmatch%|%\]|like\ \[\[\[string\ match\]\]\],\ but\ returns\ the\ index\ of\ the\ last\ character\ of\ the\ shortest\ match,\ or\ -1|&\n&|\[Pool\ (Kupries)%|%Pool%|%\]|by\ \[Andreas\ Kupries\],\ has\ various\ string\ functions,\ some\ of\ which\ are\ probably\ now\ included\ in\ \[textutil%|%tcllib::textutil%|%\]|&\n&|\[similarity%|%stringDistance%|%\]|measure\ the\ similarity\ between\ two\ strings|&\n&|\[finding\ the\ overlap\ in\ two\ strings%|%findOverlap\]|if\ andhow\ many\ of\ the\ last\ lines\ in\ \$str1\ match\ the\ first\ lines\ in\ \$str2|&\n&|\[Counting\ Characters\ in\ a\ string%|%count%|%\]|count\ characters\ in\ a\ string\]\]|&\n&|\[case:title\ -Create\ WP\ formatted\ title\ strings\ on\ the\ active\ selection%|%cate:title%|%\]|Create\ WP\ formatted\ title\ strings\ on\ the\ active\ selection|&\n\n**\ ASCII\ map\ **\n\nNo\ algorithm\ at\ all,\ but\ may\ come\ in\ handy\ \;-)\ \n\n''If\ you're\ on\ a\ UNIX\ box,\ try:\ man\ ascii''\n\n======\nproc\ ascii\ \{\}\ \{return\ \{\n\ \ \ \ 00\ nul\ \ 01\ soh\ \ 02\ stx\ \ 03\ etx\ \ 04\ eot\ \ 05\ enq\ \ 06\ ack\ \ 07\ bel\n\ \ \ \ 08\ bs\ \ \ 09\ ht\ \ \ 0a\ nl\ \ \ 0b\ vt\ \ \ 0c\ np\ \ \ 0d\ cr\ \ \ 0e\ so\ \ \ 0f\ si\n\ \ \ \ 10\ dle\ \ 11\ dc1\ \ 12\ dc2\ \ 13\ dc3\ \ 14\ dc4\ \ 15\ nak\ \ 16\ syn\ \ 17\ etb\n\ \ \ \ 18\ can\ \ 19\ em\ \ \ 1a\ sub\ \ 1b\ esc\ \ 1c\ fs\ \ \ 1d\ gs\ \ \ 1e\ rs\ \ \ 1f\ us\n\ \ \ \ 20\ sp\ \ \ 21\ \ !\ \ \ 22\ \ \"\ \ \ 23\ \ #\ \ \ 24\ \ \$\ \ \ 25\ \ %\ \ \ 26\ \ &\ \ \ 27\ \ '\n\ \ \ \ 28\ \ (\ \ \ 29\ \ )\ \ \ 2a\ \ *\ \ \ 2b\ \ +\ \ \ 2c\ \ ,\ \ \ 2d\ \ -\ \ \ 2e\ \ .\ \ \ 2f\ \ /\n\ \ \ \ 30\ \ 0\ \ \ 31\ \ 1\ \ \ 32\ \ 2\ \ \ 33\ \ 3\ \ \ 34\ \ 4\ \ \ 35\ \ 5\ \ \ 36\ \ 6\ \ \ 37\ \ 7\n\ \ \ \ 38\ \ 8\ \ \ 39\ \ 9\ \ \ 3a\ \ :\ \ \ 3b\ \ \;\ \ \ 3c\ \ <\ \ \ 3d\ \ =\ \ \ 3e\ \ >\ \ \ 3f\ \ ?\n\ \ \ \ 40\ \ @\ \ \ 41\ \ A\ \ \ 42\ \ B\ \ \ 43\ \ C\ \ \ 44\ \ D\ \ \ 45\ \ E\ \ \ 46\ \ F\ \ \ 47\ \ G\n\ \ \ \ 48\ \ H\ \ \ 49\ \ I\ \ \ 4a\ \ J\ \ \ 4b\ \ K\ \ \ 4c\ \ L\ \ \ 4d\ \ M\ \ \ 4e\ \ N\ \ \ 4f\ \ O\n\ \ \ \ 50\ \ P\ \ \ 51\ \ Q\ \ \ 52\ \ R\ \ \ 53\ \ S\ \ \ 54\ \ T\ \ \ 55\ \ U\ \ \ 56\ \ V\ \ \ 57\ \ W\n\ \ \ \ 58\ \ X\ \ \ 59\ \ Y\ \ \ 5a\ \ Z\ \ \ 5b\ \ \[\ \ \ 5c\ \ \\\ \ \ 5d\ \ \]\ \ \ 5e\ \ ^\ \ \ 5f\ \ _\n\ \ \ \ 60\ \ `\ \ \ 61\ \ a\ \ \ 62\ \ b\ \ \ 63\ \ c\ \ \ 64\ \ d\ \ \ 65\ \ e\ \ \ 66\ \ f\ \ \ 67\ \ g\n\ \ \ \ 68\ \ h\ \ \ 69\ \ i\ \ \ 6a\ \ j\ \ \ 6b\ \ k\ \ \ 6c\ \ l\ \ \ 6d\ \ m\ \ \ 6e\ \ n\ \ \ 6f\ \ o\n\ \ \ \ 70\ \ p\ \ \ 71\ \ q\ \ \ 72\ \ r\ \ \ 73\ \ s\ \ \ 74\ \ t\ \ \ 75\ \ u\ \ \ 76\ \ v\ \ \ 77\ \ w\n\ \ \ \ 78\ \ x\ \ \ 79\ \ y\ \ \ 7a\ \ z\ \ \ 7b\ \ \{\ \ \ 7c\ \ |\ \ \ 7d\ \ \}\ \ \ 7e\ \ ~\ \ \ 7f\ del\n\}\}\ \;#RS\n======\n\n**\ Linebreak\ **\n\n'''Break\ a\ string\ into\ lines\ of\ specified\ maximum\ length:'''\ \[join\]\ the\ output\ of\ this\ with\ \\n\ for\ hard-wrapped\ text:\ \n======\nproc\ linebreak\ \{s\ \{width\ 80\}\}\ \{\n\ \ \ set\ res\ \{\}\n\ \ \ while\ \{\[string\ length\ \$s\]>\$width\}\ \{\n\ \ \ \ \ \ \ set\ \ \ \ \ pos\ \[string\ wordstart\ \$s\ \$width\]\n\ \ \ \ \ \ \ lappend\ res\ \[string\ range\ \ \ \ \ \$s\ 0\ \ \ \ \[expr\ \$pos-1\]\]\n\ \ \ \ \ \ \ set\ \ \ \ \ s\ \ \ \[string\ range\ \ \ \ \ \$s\ \$pos\ end\]\n\ \ \ \}\n\ \ \ lappend\ res\ \$s\n\}\ \;#\ RS\n======\n\n\[Arjen\ Markus\]\ An\ elegant\ solution,\ but\ two\ remarks:\n\n\ \ \ *\ The\ file\ word.tcl\ remarks\ that\ word\ boundaries\ are\ platform-dependent.\ Is\ this\ also\ used\ in\ \[string\ wordstart\]?\n\ \ \ *\ More\ importantly:\ The\ above\ fails\ if\ a\ word\ is\ longer\ than\ the\ given\ width!\ You\ get\ into\ an\ endless\ loop.\n\n**\ word\ Wrap\ Via\ Tk\ Text\ Widget\ **\n\n\[D.\ McC\]:\ A\ problem\ with\ \[string\ wordstart\],\ if\ you\ want\ hard-wrapped\ text\ that\ reliably\ looks\ right,\ is\ this\ (from\ the\ \[string\ wordstart\]\ page\ on\ the\ Wiki):\ \"A\ word\ is\ considered\ to\ be\ any\ contiguous\ range\ of\ alphanumeric\ (Unicode\ letters\ or\ decimal\ digits)\ or\ underscore\ (Unicode\ connector\ punctuation)\ characters,\ ''or\ any\ single\ character\ other\ than\ these\"''\ (emphasis\ added).\ So,\ if\ you\ have\ a\ word\ (in\ the\ ordinary\ sense)\ preceded\ or\ followed\ by\ punctuation\ marks,\ \[string\ wordstart\]\ will\ treat\ the\ punctuation\ marks\ as\ separate\ \"words,\"\ and\ they\ may\ not\ come\ out\ on\ the\ same\ line\ as\ the\ word\ they\ go\ with!\n\nThe\ Tk\ text\ widget,\ with\ word\ wrap\ on,\ displays\ wrapped\ text\ that\ reliably\ looks\ right,\ with\ no\ punctuation\ marks\ separated\ from\ the\ adjoining\ words.\ So,\ to\ get\ ''hard''-wrapped\ text\ that\ looks\ right,\ you\ can\ determine\ the\ locations\ where\ the\ text\ widget\ ends\ the\ wrapped\ lines,\ and\ replicate\ the\ text\ with\ newlines\ at\ those\ locations.\ Here's\ some\ code\ I\ wrote\ that\ does\ this\ (feel\ free\ to\ suggest\ improvements).\ A\ global\ variable\ \"formawid\"\ is\ set\ to\ hold\ the\ desired\ width\ in\ characters\ of\ the\ wrapped\ text,\ and\ the\ text\ widget\ (here,\ \".tx\")\ is\ configured\ to\ that\ width,\ with\ word\ wrap:\n\n======\n\ .tx\ configure\ -width\ \$formawid\ -wrap\ \$wordwrap\n\ wm\ geometry\ .\ \{\}\ \;\ #\ Make\ sure\ the\ toplevel\ shrinks\ or\ expands\ to\ fit\n======\n\nThen,\ after\ a\ delay\ of\ one-tenth\ of\ a\ second\ (which\ seems\ to\ be\ needed\ for\ some\ reason),\ the\ following\ procedure\ is\ run.\ The\ \"whattodo\"\ arg\ can\ be\ either\ \"print\"\ (to\ prepare\ hard-wrapped\ text\ for\ printing)\ or\ \"show\"\ (to\ display\ hard-wrapped\ text\ in\ the\ text\ widget).\ If\ there\ is\ a\ selection,\ only\ the\ selected\ text\ will\ be\ hard-wrapped\;\ if\ there\ isn't,\ all\ text\ in\ the\ widget\ will\ be\ hard-wrapped.\ \n\n======\nproc\ formanew\ \{whattodo\}\ \{\n\ \ \ \ global\ formawid\n\ \ \ \ #\ Identify\ beginning\ and\ end\ of\ text\ to\ format:\n\ \ \ \ if\ \{\[.tx\ tag\ ranges\ sel\]\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ set\ selon\ 1.0\n\ \ \ \ \ \ \ \ set\ seloff\ \[.tx\ index\ end\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ selon\ \[.tx\ index\ sel.first\]\n\ \ \ \ \ \ \ \ set\ seloff\ \[.tx\ index\ sel.last\]\n\ \ \ \ \}\n\ \ \ \ set\ texin\ \[expr\ int(\$selon)\]\n\ \ \ \ set\ texend\ \[expr\ int(\$seloff)\]\n\ \ \ \ #\ Initialize\ variable\ to\ hold\ output:\n\ \ \ \ set\ formatext\ \"\"\n\ \ \ \ for\ \{set\ i\ \$texin\}\ \{\$i\ <=\ \$texend\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ #\ Get\ text\ to\ newline:\n\ \ \ \ \ \ \ \ set\ endolin\ \[.tx\ index\ \$i.end\]\n\ \ \ \ \ \ \ \ set\ endochar\ \[lindex\ \[split\ \$endolin\ \".\"\]\ end\]\n\ \ \ \ \ \ \ \ set\ whatline\ \[.tx\ get\ \$i.0\ \$endolin\]\n\ \ \ \ \ \ \ \ #\ If\ line\ is\ blank,\ insert\ only\ newline\ into\ output:\n\ \ \ \ \ \ \ \ if\ \{\[string\ trim\ \$whatline\]\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ formatext\ \"\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ If\ not,\ then\ find\ out\ where\ line\ is\ wrapped:\n\ \ \ \ \ \ \ \ for\ \{set\ c\ 1\}\ \{\$c\ <=\ \$endochar\}\ \{incr\ c\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .tx\ see\ \$i.\$c\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ceemin\ \[expr\ \{\$c-1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ boxie\ \[.tx\ get\ \$i.\$ceemin\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Get\ y\ coordinates\ of\ bounding\ boxes\ for\ adjoining\ characters:\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pixy\ \[lindex\ \[.tx\ bbox\ \$i.\$ceemin\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ nexy\ \[lindex\ \[.tx\ bbox\ \$i.\$c\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ y\ coordinate\ of\ bounding\ box\ is\ greater\ than\ for\n\ \ \ \ \ \ \ \ \ \ \ \ #\ preceding\ character,\ line\ has\ been\ wrapped,\ so\n\ \ \ \ \ \ \ \ \ \ \ \ #\ insert\ preceding\ character\ plus\ newline\ into\ output:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$nexy\ >\ \$pixy\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ formatext\ \$boxie\\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ .tx\ see\ \$i.\$c\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Otherwise,\ insert\ only\ the\ preceding\ character:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ formatext\ \$boxie\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Replicate\ existing\ newline\ from\ text\ widget:\n\ \ \ \ \ \ \ \ if\ \{\$i\ <\ \$texend\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ formatext\ \"\\n\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ if\ \{\$whattodo\ eq\ \"print\"\}\ \{\n\ \ \ \ \ \ \ \ return\ \$formatext\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ .tx\ delete\ \$selon\ \$seloff\n\ \ \ \ \ \ \ \ .tx\ insert\ \$selon\ \$formatext\n\ \ \ \ \ \ \ \ .tx\ edit\ separator\n\ \ \ \ \}\n\}\n\nafter\ 100\ formanew\n======\n\n\[hv\]\ If\ you\ want\ to\ format\ the\ lines,\ look\ into\ textutil::adjust.\ It\ can\ do\ left-,\ right-,\ or\ center-justify,\ adjust\ the\ text\ width,\ and\ do\ hyphenation.\n\n**\ Occurrence\ Count\ **\n\n'''Count\ number\ of\ occurrences\ of\ a\ substring'''\ in\ a\ string:\n\n======\nproc\ scount\ \{subs\ string\}\ \{\n\ \ \ \ regsub\ -all\ \$subs\ \$string\ \$subs\ string\n\}\nproc\ scount2\ \{subs\ string\}\ \{\n\ \ \ \ regexp\ -all\ \$subs\ \$string\ \;#\ 8.3\n\}\n======\n\nThe\ latter\ can\ also\ be\ defined\ by\ currying\ (see\ \[Custom\ curry\]):\n\n======\ninterp\ alias\ \{\}\ scount3\ \{\}\ regexp\ -all\n======\n\n\[JH\]\ writes,\ in\ a\ comp.lang.tcl\ thread\ talking\ about\ this\ subject\n======\nproc\ scount4\ \{subs\ string\}\ \{\n\ \ \ \ regexp\ -all\ ***=\$subs\ \$string\n\}\ \n======\n\nand\ \[AM\]\ initially\ proposes:\n======\nproc\ scount5\ \{subs\ string\}\ \{\n\ \ \ \ set\ count\ \[llength\ \[split\ \[string\ map\ \[list\ \$subs\ \\uFFFF\]\ \ \$string\]\ \\uFFFF\]\]\n\ \ \ \ incr\ count\ -1\ \n\}\n======\n\nbut\ that\ doesn't\ make\ use\ of\ \$string,\ so\ something\ is\ missing...\n\nStephane\ A.\ writes:\n======\nproc\ countstrings\ \{data\ search\}\ \{\n\ \ \ \ set\ l\ \[string\ length\ \$search\]\n\ \ \ \ set\ count\ 0\n\ \ \ \ while\ \{\[set\ i\ \[string\ first\ \$search\ \$data\]\]>=0\}\ \{\n\ \ \ \ \ \ \ \ incr\ count\n\ \ \ \ \ \ \ \ incr\ i\ \$l\n\ \ \ \ \ \ \ \ set\ data\ \[string\ range\ \$data\ \$i\ end\]\n\ \ \ \ \}\n\ \ \ \ set\ count\n\}\ \n======\n\n**\ Reverse\ a\ String\ **\n\n======\nproc\ srevert\ \{s\}\ \{join\ \[lreverse\ \[split\ \$s\ \"\"\]\]\ \"\"\}\ \;#RS\n======\n\nwhere\ ''lrevert''\ is\ of\ course\ on\ \[Additional\ list\ functions\]...\n\n''maybe\ it\ used\ to\ be,\ but\ I\ don't\ see\ it\ there\ now.''\ \[RS\]:\ Oops,\ it's\ named\ ''lreverse''\ there\ -\ sorry!\n\n\[WJP\]:\ That's\ because\ ''revert''\ does\ not\ have\ this\ meaning\ in\ English.\ ''revert''\ means\ ''return\ to\ a\ previous\ state''.\n''reverse''\ is\ more\ general\ in\ that\ it\ can\ have\ that\ same\ meaning\ but\ has\ other\ meanings\ including\ ''go\ backwards''\nand\ ''rearrange\ in\ the\ opposite\ orientation''.\n\n\[FW\]\ notes:\ this\ goes\ through\ a\ transitional\ list\ form.\ \ Still\ being\ a\ CPU\ speed\ and\ memory\ junkie,\ I\ feel\ obliged\ to\ correct\ this\ :P\ I'll\ call\ it\ srever''se'':\n======\nproc\ sreverse\ \{s\}\ \{\n\ \ \ \ set\ res\ \"\"\n\ \ \ \ set\ i\ \[string\ length\ \$s\]\n\ \ \ \ while\ \{\$i\ >=\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \"\$res\[string\ index\ \$s\ \[incr\ i\ -1\]\]\"\n\ \ \ \ \}\n\ \ \ \ return\ \$res\n\}\n======\n\[RS\]\ agrees,\ except\ that\ \[append\]\ may\ be\ more\ efficient:\n======\nproc\ srevert\ s\ \{\n\ \ \ \ set\ l\ \[string\ length\ \$s\]\n\ \ \ \ set\ res\ \"\"\n\ \ \ \ while\ \{\$l\}\ \{append\ res\ \[string\ index\ \$s\ \[incr\ l\ -1\]\]\}\n\ \ \ \ set\ res\n\}\n======\n\[LV\]\ notes\ that\ two\ more\ solutions\ recently\ appeared\ on\ comp.lang.tcl:\nThe\ first\ is\ by\ \[Michael\ Schlenker\]:\n======\nproc\ string_reverse\ \{str\}\ \{\n\ \ \ \ set\ rts\ \"\"\n\ \ \ \ for\ \{set\ i\ \[string\ length\ \$str\]\;\ incr\ i\ -1\}\ \{\$i\ >=\ 0\}\ \{incr\ i\ -1\}\ \{\n\ \ \ \ \ \ \ \ append\ rts\ \[string\ index\ \$str\ \$i\]\n\ \ \ \ \}\n\ \ \ \ return\ \$rts\n\}\n======\nand\ the\ second\ by\ \[(R.\ T.\ Wurth\]:\n\n======\nproc\ srev\ s\ \{\n\ \ \ \ return\ \[join\ \[::struct::list\ reverse\ \[split\ \$s\ \{\}\]\]\ \{\}\]\n\}\n======\n\n\[Am\]\ (13\ december\ 2005)\ The\ question\ came\ up\ again\ in\ the\ chatroom\ yesterday,\ and\ I\ decided\ to\ measure\ the\ performance\ of\ various\ alternatives\ ...\ See:\ \[Performance\ of\ string\ reversing\ algorithms\]\n\n**\ Longest\ Common\ Prefix\ **\n\nAlso\ found\ in\ \[textutil%|%tcllib::textutil\]\n\n\[Arjen\ Markus\]\ At\ times\ I\ have\ had\ the\ need\ (not\ too\ urgent\ though)\ of\ a\ function/proc\ to\ determine\ the\ position\ where\ two\ strings\ (or\ lists)\ become\ different:\n\n\ \ \ \"Arjen\ Markus\"\ versus\ \"Arjen\ Marcus\"\ -->\ position:\ 9\n\ \ \ \"Arjen\ Markus\"\ versus\ \"Arjan\ Markus\"\ -->\ position:\ 3\n\n(though\ mostly\ these\ are\ cases\ where\ my\ name\ and\ the\ variations\ that\ I\ commonly\ encounter\ are\ not\ involved)\ -\ \[RS\]:\ That\ would\ be\ the\ length\ of\ the\ common\ prefix\ which\ one\ might\ implement\ like\ this:\n======\nproc\ commonPrefix\ \{a\ b\}\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ foreach\ i\ \[split\ \$a\ \"\"\]\ j\ \[split\ \$b\ \"\"\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\$i==\$j\}\ \{append\ res\ \$i\}\ else\ break\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\n======\n\nHere\ is\ a\ generalized\ version\ that\ takes\ any\ number\ of\ strings\ and\ returns\ the\ prefix\ which\ all\ have\ in\ common:\n\n======\nproc\ longestCommonPrefix\ strings\ \{\n\ \ \ set\ res\ \{\}\n\ \ \ set\ i\ 0\n\ \ \ foreach\ char\ \[split\ \[lindex\ \$strings\ 0\]\ \"\"\]\ \{\n\ \ \ \ \ \ \ foreach\ string\ \[lrange\ \$strings\ 1\ end\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$string\ \$i\]\ !=\ \$char\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$res\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ append\ res\ \$char\n\ \ \ \ \ \ \ incr\ i\n\ \ \ \}\n\ \ \ set\ res\n\}\ \;#\ RS\n======\n\n''\[MGS\]\ \[\[2004/05/13\]\]''\ -\ Here's\ another\ way\ -\ sort\ a\ list\ of\ strings\ and\ then\ compare\ the\ first\ and\ last:\n\n======\nproc\ string:common\ \{string1\ string2\}\ \{\n\ \ \ \ set\ i\ 1\n\ \ \ \ while\ \{\ \[string\ equal\ -length\ \$i\ \$string1\ \$string2\]\ \}\ \{\ incr\ i\ \}\n\ \ \ \ return\ \[string\ range\ \$string1\ 0\ \[expr\ \{\$i-2\}\]\]\n\}\n\nproc\ string:common:list\ \{args\}\ \{\n\ \ \ \ if\ \{\ \[llength\ \$args\]\ <\ 2\ \}\ \{\n\ \ \ \ \ \ \ \ return\ -code\ error\ \"wrong\ #\ args:\ must\ be\ >=\ 2\"\n\ \ \ \ \}\n\ \ \ \ set\ list\ \[lsort\ \$args\]\n\ \ \ \ return\ \[string:common\ \[lindex\ \$list\ 0\]\ \[lindex\ \$list\ end\]\]\n\}\n======\n\n''\[JEC\]\ \[\[2010/03/18\]\]''\ notes\ the\ above\ string:common\ has\ a\ bug\ and\ never\ returns\ on\ identical\ strings.\ \ Even\ when\ fixed\ \ it\ does\ O(n^2)\ comparisons\n\n''\[BBH\]\ \[\[2004/05/13\]\]''\ \ -\ This\ got\ me\ thinking\ that\ RE\ back\ references\ would\ be\ a\ perfect\ fit,\ a\ little\ playing\ &\ it\ turns\ out\ I\ was\ right\ \;)\n\n======\nproc\ prefix\ \{s1\ s2\}\ \{\n\ \ \ \ regexp\ \{^(.*).*\\0\\1\}\ \"\$s1\\0\$s2\"\ all\ pref\n\ \ \ \ return\ \$pref\n\}\n======\n\nand\ easily\ generalized\ for\ multiple\ words\n\n======\nproc\ prefix\ \{str\ args\}\ \{\n\ \ \ \ set\ re\ \{^(.*).*\}\n\ \ \ \ foreach\ s\ \$args\ \{\n\ \ \ \ \ \ \ \ append\ re\ \{\\0\\1.*\}\n\ \ \ \ \ \ \ \ append\ str\ \"\\0\$s\"\n\ \ \ \ \}\n\ \ \ \ regexp\ \$re\ \$str\ all\ pref\n\ \ \ \ return\ \$pref\n\}\n======\n\n\[NEM\]\ 17Mar2005\ -\ Another\ RE\ variation:\n\n======\nproc\ reprefix\ \{str1\ str2\}\ \{\n\ \ \ \ regexp\ -inline\ ^\[join\ \[split\ \$str1\ \"\"\]\ ?\]?\ \$str2\n\}\n======\n\n\[NEM\]\ 5mins\ later.\ 'Tis\ broken:\n\n\ %\ reprefix\ iamadonut\ iamatoilet\n\ iamat\n\nWhoops.\n----\n\n**\ Subscripts\ **\n\nThe\ characters\ for\ which\ subscript\ versions\ exist\ in\ Unicode\ (digits,\ parens,\ some\ operators\ -see\ the\ list\ in\ code)\ are\ converted\ to\ their\ subscripted\ Unicodes.\ Others\ are\ left\ unchanged.\ (For\ superscripts\ the\ positions\ 1,2,3\ seem\ not\ to\ be\ filled\ in\ my\ installation,\ so\ I\ didn't\ add\ the\ corresponding\ code...)\n\n======\nproc\ subscript\ s\ \{\n\ \ \ \ set\ res\ \"\"\n\ \ \ \ foreach\ char\ \[split\ \$s\ \"\"\]\ \{\n\ \ \ \ \ \ \ \ set\ pos\ \[lsearch\ -exact\ \{0\ 1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ +\ -\ =\ (\ )\}\ \$char\]\n\ \ \ \ \ \ \ \ if\ \{\$pos>=0\}\ \{set\ char\ \[format\ %c\ \[incr\ pos\ 0x2080\]\]\}\n\ \ \ \ \ \ \ \ append\ res\ \$char\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n%\ puts\ H\[subscript\ 2\]O\nH?O\n======\n\n**\ Strictly\ a\ Floating\ Point\ Number\ **\n\nthe\ regular\ ''\[string\]\ is\ double''\ term\ fires\ on\ integers\ too.\ The\ following\ fires\ on\ real\ floats\ only:\n======\nproc\ isFloat\ x\ \{expr\ \{\[string\ is\ double\ -strict\ \$x\]\ &&\ !\[string\ is\ int\ \$x\]\}\}\ \;#RS\n======\n\n**\ Sort\ a\ String\ **\n\n\[AM\]\ For\ some\ symbolic\ manipulations\ (w.r.t.\ group\ theory,\ oh\ just\ for\ the\ fun\ of\ it),\ I\ need\ to\ sort\ the\ characters\ in\ a\ string,\ so\ that\ for\ instance\ \"ababa\"\ becomes\ \"aaabb\".\n\nThis\ can\ be\ done\ via:\n\n======\nproc\ charsort\ \{\ string\ \}\ \ \{\n\ \ \ return\ \[join\ \[lsort\ \[split\ \$string\ \{\}\]\ \]\ \{\}\ \]\n\}\n======\n\n**\ Longest\ String\ **\n\nHere's\ a\ little\ proc\ to\ find\ the\ length\ of\ the\ longest\ string\ in\ a\ list:\n\n======\nproc\ maxlen\ \{args\}\ \{\n\ \ \ \ #\ Written\ 2003\ by\ Ed\ Suominen,\ hereby\ placed\ in\ the\ public\ domain\n\ \ \ \ if\ \{\ \[llength\ \$args\]\ >\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ if\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \[set\ x\ \[string\ length\ \[lindex\ \$args\ 0\]\]\]\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \[set\ y\ \[string\ length\ \[lindex\ \$args\ 1\]\]\]\ <\ 0\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -1\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\ \$x\ ==\ \$y\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 1\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x\ \[lsort\ -decreasing\ -command\ maxlen\ \[lindex\ \$args\ 0\]\]\n\ \ \ \ \ \ \ \ return\ \[string\ length\ \[lindex\ \$x\ 0\]\]\n\ \ \ \ \}\n\}\n======\n\nAlternative:\n\n======\nproc\ maxlen\ args\ \{\n\ \ \ \ if\ \{\[llength\ \$args\]==1\}\ \{set\ args\ \[lindex\ \$args\ 0\]\}\n\ \ \ \ set\ res\ \[string\ length\ \[lindex\ \$args\ 0\]\]\n\ \ \ \ foreach\ i\ \[lrange\ \$args\ 1\ end\]\ \{\n\ \ \ \ \ \ \ \ set\ l2\ \[string\ length\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$l2\ >\ \$res\}\ \{set\ res\ \$l2\}\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n======\n\n**\ String\ Insert\ **\n\n'''Insert\ a\ string\ into\ another'''\ at\ a\ given\ position,\ analogous\ to\ \[linsert\]:\n\n======\nproc\ strinsert\ \{string\ pos\ char\}\ \{\n\ \ \ \ set\ original\ \[string\ index\ \$string\ \$pos\]\n\ \ \ \ string\ replace\ \$string\ \$pos\ \$pos\ \$char\$original\n\}\ \;#\ RS\n%\ strinsert\ hello\ 1\ x\nhxello\n======\n\n**\ Substition\ that\ Preserves\ Grouping\ **\n\n\[RHS\]\ ''23Feb2005''\ There\ have\ been\ a\ number\ of\ times\ where\ I\ have\ wanted\ a\ version\ of\ '''subst'''\ that\ preserves\ grouping.\ For\ example,\ I\ want\ to\ be\ able\ to\ do\ the\ following:\n\n======\n%\ array\ set\ myarr\ \[subst\ \{\n\ \ \ \ a\ \$x\n\ \ \ \ b\ \[getConfigValue\ something\]\n\ \ \ \ c\ \{\n\ \ \ \ \ \ \ \ a\ b\n\ \ \ \ \ \ \ \ c\ d\n\ \ \ \ \}\n\}\]\n%\ array\ get\ myArr\na\ 1\ b\ blah\ c\ \{\n\ \ \ \ \ \ \ \ a\ b\n\ \ \ \ \ \ \ \ c\ d\n\ \ \ \ \}\n======\n\nMy\ main\ reason\ for\ this\ is,\ when\ the\ dataset\ get\ large,\ I\ tend\ to\ find\ \\\ line\ continuations\ fairly\ ugly...\ That,\ and\ my\ emacs\ config\ doesn't\ indent\ well\ for\ multiple\ levels\ of\ line\ continuations\ if\ there's\ sub\ levels.\n\nIn\ pursuit\ of\ the\ above,\ I\ came\ up\ with\ the\ following:\n======\nproc\ gsubst\ \{input\}\ \{\n\ \ \ \ set\ data\ \{\}\n\ \ \ \ foreach\ line\ \[split\ \$input\ \\n\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\ \[info\ complete\ \$data\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ data\ \"\ \$line\"\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ data\ \"\\n\$line\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ uplevel\ 1\ list\ \$data\n\}\n======\n\nThe\ above\ proc\ should,\ in\ theory,\ cause\ the\ following\ two\ to\ work\ exactly\ the\ same\n\ list\ a\ 1\ \\\n\ \ \ \ \ \ b\ \$x\ \\\n\ \ \ \ \ \ c\ \{\n\ \ \ \ \ \ \ \ \ \ 1\n\ \ \ \ \ \ \ \ \ \ 2\n\ \ \ \ \ \ \}\ \\\n\ \ \ \ \ \ d\ \[somecommand\]\n\ gsubst\ \{\n\ \ \ \ \ \ a\ 1\n\ \ \ \ \ \ b\ \$x\n\ \ \ \ \ \ c\ \{\n\ \ \ \ \ \ \ \ \ \ 1\n\ \ \ \ \ \ \ \ \ \ 2\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ d\ \[somecommand\]\n\ \}\n----\n\n\[\[What\ should\ the\ category\ be\ for\ this?\]\]\ \[RS\]:\ Hm..\ \"Additional\"?\ That's\ the\ criterion\ I\ quickly\ search\ this\ set\ of\ pages\ with\ -\ such\ takeaway\ snippets\ used\ to\ be\ in\ the\ \[Bag\ of\ algorithms\]\ until\ it\ grew\ too\ thick.\n\n**\ N-th\ Occurrence\ of\ a\ Substring\ **\n\n\[Silas\]\ -\ 2005.10.14\ -\ If\ you\ want\ to\ find\ the\ third\ or\ fourth\ ocurrance\ of\ a\ string\ in\ another\ string,\ you'll\ have\ to\ use\ \[string\ first\]\ many\ times.\ The\ following\ proc\ could\ help:\n\n**\ String\ to\ Proper\ English\ Title\ **\n\n\[D.\ McC\]:\ \ Oct\ 20\ 2005\ -\ The\ \"string\ totitle\"\ subcommand\ only,\ and\ always,\ capitalizes\ the\ first\ letter\ in\ a\ string,\ no\ matter\ how\ many\ words\ are\ in\ the\ string\ or\ what\ the\ words\ are.\ Here's\ some\ code\ to\ convert\ a\ multiple-word\ expression\ in\ English\ to\ a\ properly\ capitalized\ title,\ in\ which\ all\ initial\ letters\ are\ capitalized\ except\ those\ of\ articles,\ conjunctions,\ and\ prepositions\ with\ four\ or\ fewer\ letters.\ '''(Needs\ improvement--see\ revised\ version,\ farther\ below)'''\n\n======\nproc\ title\ \{str\}\ \{\n\ \ \ \ set\ output\ \"\"\n\ \ \ \ set\ nocaps\ \[list\ a\ an\ and\ at\ but\ by\ for\ from\ in\ into\ of\ on\ or\ the\ to\ with\]\n\ \ \ \ foreach\ word\ \[split\ \$str\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\[lsearch\ \$nocaps\ \$word\]\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ totitle\ \$word\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ append\ output\ \"\$word\ \"\n\ \ \ \ \}\n\ \ \ \ return\ \[string\ trim\ \$output\]\n\}\n======\n\nExample:\n\n\ %\ set\ bogomips\ \"groundwork\ of\ the\ metaphysics\ of\ balderdash\"\n\ groundwork\ of\ the\ metaphysics\ of\ balderdash\n\ %\ title\ \$bogomips\n\ Groundwork\ of\ the\ Metaphysics\ of\ Balderdash\n\n\[DKF\]:\ Cool!\ It's\ not\ quite\ right\ though.\ The\ following\ gets\ closer,\ but\ isn't\ right\ yet\ either\ (testing\ on\ your\ paragraph\ above,\ of\ course!)\n======\nproc\ title\ \{str\}\ \{\n\ \ \ \ set\ output\ \"\"\n\ \ \ \ set\ nocaps\ \{a\ an\ and\ at\ but\ by\ for\ from\ in\ into\ of\ on\ or\ the\ to\ with\}\n\ \ \ \ foreach\ word\ \[regexp\ -all\ -inline\ \{\[\\w'.\]+|\\W+\}\ \$str\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \{\[A-Za-z\]*\}\ \$word\]\ &&\ \[lsearch\ \$nocaps\ \$word\]\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ In\ 8.5\ should\ use\ the\ 'ni'\ operator\ instead\ of\ the\ \[lsearch\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ totitle\ \$word\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ append\ output\ \$word\n\ \ \ \ \}\n\ \ \ \ return\ \[string\ trim\ \$output\]\n\}\n======\n\n\[LES\]\ You\ forget\ that\ you'll\ want\ those\ \"nocaps\"\ words\ to\ be\ turned\ to\ title\ if\ they\ begin\ a\ sentence.\ Here\ is\ a\ proc\ I\ use\ to\ rename\ files\ (usually\ mp3).\ It\ doesn't\ handle\ punctuation,\ but\ handles\ hyphens,\ e.g.:\ \"Artist\ -\ A\ Song\ Title\".\ Tweaking\ it\ to\ also\ take\ punctuation\ (periods\ or\ first\ word\ of\ title)\ in\ consideration\ should\ be\ trivial.\ That\ is\ not\ desired\ in\ file\ renaming\ because\ periods\ (dots)\ do\ not\ mean\ the\ same\ as\ in\ regular\ titles.\n\n======\nproc\ mp3\ args\ \ \{\n\ \ \ \ set\ _nocaps\ \{\n\ \ \ \ \ \ \ \ a\ as\ à\ às\ ao\ aos\ de\ da\ das\ do\ dos\ e\ em\ na\ nas\ no\ nos\ \n\ \ \ \ \ \ \ \ o\ os\ ou\ para\ por\ que\ sem\ sob\n\ \ \ \ \ \ \ \ an\ and\ are\ at\ but\ for\ from\ if\ in\ is\ it's\ not\ of\ on\ or\ \n\ \ \ \ \ \ \ \ the\ to\ under\ vs\ vs.\ with\ without\n\ \ \ \ \ \ \ \ au\ aux\ avec\ dans\ des\ en\ et\ le\ la\ les\ ou\ par\ pour\ qui\ si\n\ \ \ \ \ \ \ \ con\ del\ el\ en\ la\ las\ los\ sin\ y\n\ \ \ \ \}\;\ #\ German\ and\ Italian,\ anyone?\n\ \n\ \ \ \ foreach\ _file\ \[\ glob\ *\ \]\ \{\ \n\ \ \ \ \ \ \ \ if\ \{\ \$_file\ eq\ \{.:\}\ \}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ #\ lowercase\ the\ whole\ name\n\ \ \ \ \ \ \ \ set\ _old\ \ \$_file\n\ \ \ \ \ \ \ \ set\ _file\ \[string\ tolower\ \$_file\]\n\ \ \ \ \ \ \ \ set\ _new\ \{\}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \;#\ empty\ _new\ in\ each\ iteration\n\ \ \ \ \ \ \ \ set\ _c\ \ \ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \;#\ zero\ counter\ in\ each\ iteration\n\ \n\ \ \ \ \ \ \ \ foreach\ _word\ \$_file\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ incr\ _c\n\ \n\ \ \ \ \ \ \ \ \ \ \ \ #\ anything\ right\ after\ \"\ -\ \"\ probably\ is\ the\ first\ word\ of\ a\ phrase.\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ current\ word\ is\ \"-\",\ reset\ counter\ so\ next\ word\ is\ 1\ and\ gets\ caps\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \$_word\ eq\ \"-\"\ \}\ \{\ set\ _c\ 0\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ current\ word\ is\ 1,\ it\ gets\ caps\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \$_c\ ==\ 1\ \}\ \{\ set\ _word\ \[string\ totitle\ \$_word\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ it\ is\ not\ in\ exceptions,\ it\ gets\ caps\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \[lsearch\ \$_nocaps\ \$k\ \]\ <\ 0\ \}\ \ \ \ \ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ k\ \[string\ totitle\ \$k\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ add\ the\ word\ to\ the\ new\ name\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ _new\ \$k\n\ \ \ \ \ \ \ \ \}\n\ \n\ \ \ \ \ \ \ \ #\ UNCOMMENT\ the\ two\ next\ lines\ if\ you\ want\ files\ renamed\ automatically\n\ \ \ \ \ \ \ \ #file\ rename\ \ \$_old\ \ RENAME_TEMP\n\ \ \ \ \ \ \ \ #file\ rename\ \ RENAME_TEMP\ \ \$_new\n\ \ \ \ \ \ \ \ puts\ \ \"\$_old\\n\$_new\\n\"\n\ \ \ \ \}\n\}\n======\n\n\[D.\ McC\]:\ \ OK,\ I\ do\ want\ the\ \"nocaps\"\ words\ capitalized\ if\ they\ (1)\ begin\ the\ title\ or\ (2)\ come\ right\ after\ a\ colon.\ Also,\ as\ I\ belatedly\ noticed,\ quotation\ marks\ need\ to\ be\ stripped\ out\ for\ \"string\ totitle\"\ to\ work\ right,\ but\ then\ put\ back\ into\ the\ finished\ product.\ I'd\ go\ a\ long\ way\ to\ avoid\ a\ regular\ expression\ like\ \{\[\\w'.\]+|\\W+\},\ though.\ Let's\ try\ this:\n\n======\nproc\ title\ \{str\}\ \{\n\ \ \ \ set\ output\ \"\"\n\ \ \ \ set\ nocaps\ \[list\ a\ an\ and\ at\ but\ by\ for\ from\ in\ into\ of\ on\ or\ the\ to\ with\]\n\ \ \ \ set\ count\ 0\n\ \ \ \ foreach\ word\ \[split\ \$str\]\ \{\n\ \ \ \ \ \ \ \ #\ Strip\ quotation\ marks:\n\ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$word\ 0\]\ ==\ \"\\\"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ quote\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ trim\ \$word\ \\\"\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ quote\ 0\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Always\ capitalize\ the\ first\ word\;\ otherwise,\n\ \ \ \ \ \ \ \ #\ don't\ capitalize\ any\ words\ in\ the\ \"nocaps\"\ list:\n\ \ \ \ \ \ \ \ if\ \{\$count\ ==\ 0\ ||\ \[lsearch\ \$nocaps\ \$word\]\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ totitle\ \$word\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Add\ word\ plus\ space,\ with\ or\ without\ quotation\ marks,\ to\ output:\n\ \ \ \ \ \ \ \ if\ \{\$quote\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ output\ \"\\\"\$word\\\"\ \"\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ output\ \"\$word\ \"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Capitalize\ any\ word\ after\ a\ colon:\n\ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$word\ end\]\ ==\ \":\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ count\ 0\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ count\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \[string\ trim\ \$output\]\n\}\n======\n\nExample:\n\n\ %\ set\ wordsworth\ \{what\ I\ say\ is:\ by\ gum,\ give\ me\ the\ finest\ \"bogomips\"\ in\ the\ universe!\}\n\ what\ I\ say\ is:\ by\ gum,\ give\ me\ the\ finest\ \"bogomips\"\ in\ the\ universe!\n\ %\ title\ \$wordsworth\n\ What\ I\ Say\ Is:\ By\ Gum,\ Give\ Me\ the\ Finest\ \"Bogomips\"\ in\ the\ Universe!\n\n======\nproc\ mystringFirst\ \{substring\ mystring\ ocorrencia\}\ \{\n\ \ \ \ if\ \{!\$ocorrencia\}\ \{return\ -1\}\n\ \ \ \ set\ index\ 0\n\ \ \n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$ocorrencia\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ index\ \[string\ first\ \$substring\ \$mystring\]\n\ \ \ \ \ \ \ \ set\ mystring\ \[string\ range\ \$mystring\ \[expr\ \$index\ +\ 1\]\ \[string\ length\ \$mystring\]\]\n\ \ \ \ \}\n\ \ \n\ \ \ \ return\ \$index\n\}\n======\n#\ Here's\ an\ example\ that\ doesn't\ use\ foreach.\n\nproc\ title-case\ \{text\}\ \{\n\ \ \ \ for\ \{set\ index\ 0\}\ \{\$index\ <\ \[string\ length\ \$text\]\}\ \{incr\ index\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\ \[string\ wordstart\ \$text\ \$index\]\ ==\ \$index\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[string\ replace\ \$text\ \$index\ \$index\ \[string\ toupper\ \[string\ index\ \$text\ \$index\]\]\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[string\ replace\ \$text\ \$index\ \$index\ \[string\ tolower\ \[string\ index\ \$text\ \$index\]\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$text\n\}\n======\n**\ Misc\ **\n\nLV:\ Take\ a\ look\ at\ \[Tcl-FAQ\]'s\ part\ 5\ to\ gather\ ideas\ on\ other\npackages\ with\ string\ functions.\n\n----\n\n'''Letterspacing:'''\ spreading\ a\ string\ by\ inserting\ blanks\ between\ each\ two\ characters.\ \[KBK\]\ notes\ that\ there's\ a\ printer's\ proverb:\ Anyone\ who\ would\ l\ e\ t\ t\ e\ r\ s\ p\ a\ c\ e\ \ \ \ l\ o\ w\ e\ r\ c\ a\ s\ e\ \ \ would\ steal\ sheep.\ Simply\ functional:\n======\nproc\ letterspace\ s\ \{join\ \[split\ \$s\ \"\"\]\ \"\ \"\}\ \;#\ RS\n%\ letterspace\ \"steal\ sheep\"\ns\ t\ e\ a\ l\ \ \ s\ h\ e\ e\ p\n======\n\nIn\ the\ book\ ''Stop\ Stealing\ Sheep\ &\ find\ out\ how\ type\ works,''\ by\ Erik\ Spiekermann\ and\ E.M.\ Ginger,\nAdobe\ Press,\ 1993,\ on\ page\ 7,\ in\ the\ side\ bar\ the\ quotation\ attributed\ to\ Frederic\ Goudy\ was,\n\"Anyone\ who\ would\ letterspace\ black\ letter\ would\ steal\ sheep.\"\ --\ \[escargo\]\n\n\n<<categories>>\ Category\ Discussion\ |\ Category\ Example\ |\ Category\ String\ Processing regexp2} CALL {my render {Additional string functions} This\ page\ describes\ various\ string\ processing\ that\ exist\ beside\ the\ standard\ commands\n\n<<TOC>>\n\n**\ List\ **\n\n%|name|description|%\n&|\[texutil%|%adjust%|%\]||&\n&|\[texutil%|%tcllib::textutil::adjust%|%\]||&\n&|\[texutil%|%tcllib::textutil::readPatterns%|%\]||&\n&|\[texutil%|%tcllib::textutil::listPredefined%|%\]||&\n&|\[texutil%|%tcllib::textutil::getPredefined%|%\]||&\n&|\[texutil%|%tcllib::textutil::indent%|%\]||&\n&|\[texutil%|%tcllib::textutil::undent%|%\]||&\n&|\[texutil%|%tcllib::textutil::splitn%|%\]||&\n&|\[texutil%|%tcllib::textutil::splitx%|%\]||&\n&|\[texutil%|%tcllib::textutil::tabify%|%\]||&\n&|\[texutil%|%tcllib::textutil::tabify2%|%\]||&\n&|\[texutil%|%tcllib::textutil::trim%|%\]||&\n&|\[texutil%|%tcllib::textutil::trimleft%|%\]||&\n&|\[texutil%|%tcllib::textutil::trimrigth%|%\]||&\n&|\[texutil%|%tcllib::textutil::trimprefix%|%\]||&\n&|\[texutil%|%tcllib::textutil::trimEmptyHeading%|%\]||&\n&|\[texutil%|%tcllib::textutil::untabify%|%\]||&\n&|\[texutil%|%tcllib::textutil::untabify2%|%\]||&\n&|\[texutil%|%tcllib::textutil::repeat%|%\]||&\n&|\[texutil%|%tcllib::textutil::blank%|%\]||&\n&|\[texutil%|%tcllib::textutil::chop%|%\]||&\n&|\[texutil%|%tcllib::textutil::tail%|%\]||&\n&|\[texutil%|%tcllib::textutil::cap%|%\]||&\n&|\[texutil%|%tcllib::textutil::uncap%|%\]||&\n&|\[texutil%|%tcllib::textutil::longestCommonPrefixList%|%\]||&\n&|\[texutil%|%tcllib::textutil::longestCommonPrefix%|%\]||&\n&|\[ycl%|%delimit%|%\]|split\ (partition)\ a\ string\ into\ substrings\ using\ any\ combination\ of\ string,\ match,\ or\ regular\ expressions,\ returning\ both\ the\ substrings\ and\ the\ delimiters.|&\n&|\[ycl%|%shortmatch%|%\]|like\ \[\[\[string\ match\]\]\],\ but\ returns\ the\ index\ of\ the\ last\ character\ of\ the\ shortest\ match,\ or\ -1|&\n&|\[Pool\ (Kupries)%|%Pool%|%\]|by\ \[Andreas\ Kupries\],\ has\ various\ string\ functions,\ some\ of\ which\ are\ probably\ now\ included\ in\ \[textutil%|%tcllib::textutil%|%\]|&\n&|\[similarity%|%stringDistance%|%\]|measure\ the\ similarity\ between\ two\ strings|&\n&|\[finding\ the\ overlap\ in\ two\ strings%|%findOverlap\]|if\ andhow\ many\ of\ the\ last\ lines\ in\ \$str1\ match\ the\ first\ lines\ in\ \$str2|&\n&|\[Counting\ Characters\ in\ a\ string%|%count%|%\]|count\ characters\ in\ a\ string\]\]|&\n&|\[case:title\ -Create\ WP\ formatted\ title\ strings\ on\ the\ active\ selection%|%cate:title%|%\]|Create\ WP\ formatted\ title\ strings\ on\ the\ active\ selection|&\n\n**\ ASCII\ map\ **\n\nNo\ algorithm\ at\ all,\ but\ may\ come\ in\ handy\ \;-)\ \n\n''If\ you're\ on\ a\ UNIX\ box,\ try:\ man\ ascii''\n\n======\nproc\ ascii\ \{\}\ \{return\ \{\n\ \ \ \ 00\ nul\ \ 01\ soh\ \ 02\ stx\ \ 03\ etx\ \ 04\ eot\ \ 05\ enq\ \ 06\ ack\ \ 07\ bel\n\ \ \ \ 08\ bs\ \ \ 09\ ht\ \ \ 0a\ nl\ \ \ 0b\ vt\ \ \ 0c\ np\ \ \ 0d\ cr\ \ \ 0e\ so\ \ \ 0f\ si\n\ \ \ \ 10\ dle\ \ 11\ dc1\ \ 12\ dc2\ \ 13\ dc3\ \ 14\ dc4\ \ 15\ nak\ \ 16\ syn\ \ 17\ etb\n\ \ \ \ 18\ can\ \ 19\ em\ \ \ 1a\ sub\ \ 1b\ esc\ \ 1c\ fs\ \ \ 1d\ gs\ \ \ 1e\ rs\ \ \ 1f\ us\n\ \ \ \ 20\ sp\ \ \ 21\ \ !\ \ \ 22\ \ \"\ \ \ 23\ \ #\ \ \ 24\ \ \$\ \ \ 25\ \ %\ \ \ 26\ \ &\ \ \ 27\ \ '\n\ \ \ \ 28\ \ (\ \ \ 29\ \ )\ \ \ 2a\ \ *\ \ \ 2b\ \ +\ \ \ 2c\ \ ,\ \ \ 2d\ \ -\ \ \ 2e\ \ .\ \ \ 2f\ \ /\n\ \ \ \ 30\ \ 0\ \ \ 31\ \ 1\ \ \ 32\ \ 2\ \ \ 33\ \ 3\ \ \ 34\ \ 4\ \ \ 35\ \ 5\ \ \ 36\ \ 6\ \ \ 37\ \ 7\n\ \ \ \ 38\ \ 8\ \ \ 39\ \ 9\ \ \ 3a\ \ :\ \ \ 3b\ \ \;\ \ \ 3c\ \ <\ \ \ 3d\ \ =\ \ \ 3e\ \ >\ \ \ 3f\ \ ?\n\ \ \ \ 40\ \ @\ \ \ 41\ \ A\ \ \ 42\ \ B\ \ \ 43\ \ C\ \ \ 44\ \ D\ \ \ 45\ \ E\ \ \ 46\ \ F\ \ \ 47\ \ G\n\ \ \ \ 48\ \ H\ \ \ 49\ \ I\ \ \ 4a\ \ J\ \ \ 4b\ \ K\ \ \ 4c\ \ L\ \ \ 4d\ \ M\ \ \ 4e\ \ N\ \ \ 4f\ \ O\n\ \ \ \ 50\ \ P\ \ \ 51\ \ Q\ \ \ 52\ \ R\ \ \ 53\ \ S\ \ \ 54\ \ T\ \ \ 55\ \ U\ \ \ 56\ \ V\ \ \ 57\ \ W\n\ \ \ \ 58\ \ X\ \ \ 59\ \ Y\ \ \ 5a\ \ Z\ \ \ 5b\ \ \[\ \ \ 5c\ \ \\\ \ \ 5d\ \ \]\ \ \ 5e\ \ ^\ \ \ 5f\ \ _\n\ \ \ \ 60\ \ `\ \ \ 61\ \ a\ \ \ 62\ \ b\ \ \ 63\ \ c\ \ \ 64\ \ d\ \ \ 65\ \ e\ \ \ 66\ \ f\ \ \ 67\ \ g\n\ \ \ \ 68\ \ h\ \ \ 69\ \ i\ \ \ 6a\ \ j\ \ \ 6b\ \ k\ \ \ 6c\ \ l\ \ \ 6d\ \ m\ \ \ 6e\ \ n\ \ \ 6f\ \ o\n\ \ \ \ 70\ \ p\ \ \ 71\ \ q\ \ \ 72\ \ r\ \ \ 73\ \ s\ \ \ 74\ \ t\ \ \ 75\ \ u\ \ \ 76\ \ v\ \ \ 77\ \ w\n\ \ \ \ 78\ \ x\ \ \ 79\ \ y\ \ \ 7a\ \ z\ \ \ 7b\ \ \{\ \ \ 7c\ \ |\ \ \ 7d\ \ \}\ \ \ 7e\ \ ~\ \ \ 7f\ del\n\}\}\ \;#RS\n======\n\n**\ Linebreak\ **\n\n'''Break\ a\ string\ into\ lines\ of\ specified\ maximum\ length:'''\ \[join\]\ the\ output\ of\ this\ with\ \\n\ for\ hard-wrapped\ text:\ \n======\nproc\ linebreak\ \{s\ \{width\ 80\}\}\ \{\n\ \ \ set\ res\ \{\}\n\ \ \ while\ \{\[string\ length\ \$s\]>\$width\}\ \{\n\ \ \ \ \ \ \ set\ \ \ \ \ pos\ \[string\ wordstart\ \$s\ \$width\]\n\ \ \ \ \ \ \ lappend\ res\ \[string\ range\ \ \ \ \ \$s\ 0\ \ \ \ \[expr\ \$pos-1\]\]\n\ \ \ \ \ \ \ set\ \ \ \ \ s\ \ \ \[string\ range\ \ \ \ \ \$s\ \$pos\ end\]\n\ \ \ \}\n\ \ \ lappend\ res\ \$s\n\}\ \;#\ RS\n======\n\n\[Arjen\ Markus\]\ An\ elegant\ solution,\ but\ two\ remarks:\n\n\ \ \ *\ The\ file\ word.tcl\ remarks\ that\ word\ boundaries\ are\ platform-dependent.\ Is\ this\ also\ used\ in\ \[string\ wordstart\]?\n\ \ \ *\ More\ importantly:\ The\ above\ fails\ if\ a\ word\ is\ longer\ than\ the\ given\ width!\ You\ get\ into\ an\ endless\ loop.\n\n**\ word\ Wrap\ Via\ Tk\ Text\ Widget\ **\n\n\[D.\ McC\]:\ A\ problem\ with\ \[string\ wordstart\],\ if\ you\ want\ hard-wrapped\ text\ that\ reliably\ looks\ right,\ is\ this\ (from\ the\ \[string\ wordstart\]\ page\ on\ the\ Wiki):\ \"A\ word\ is\ considered\ to\ be\ any\ contiguous\ range\ of\ alphanumeric\ (Unicode\ letters\ or\ decimal\ digits)\ or\ underscore\ (Unicode\ connector\ punctuation)\ characters,\ ''or\ any\ single\ character\ other\ than\ these\"''\ (emphasis\ added).\ So,\ if\ you\ have\ a\ word\ (in\ the\ ordinary\ sense)\ preceded\ or\ followed\ by\ punctuation\ marks,\ \[string\ wordstart\]\ will\ treat\ the\ punctuation\ marks\ as\ separate\ \"words,\"\ and\ they\ may\ not\ come\ out\ on\ the\ same\ line\ as\ the\ word\ they\ go\ with!\n\nThe\ Tk\ text\ widget,\ with\ word\ wrap\ on,\ displays\ wrapped\ text\ that\ reliably\ looks\ right,\ with\ no\ punctuation\ marks\ separated\ from\ the\ adjoining\ words.\ So,\ to\ get\ ''hard''-wrapped\ text\ that\ looks\ right,\ you\ can\ determine\ the\ locations\ where\ the\ text\ widget\ ends\ the\ wrapped\ lines,\ and\ replicate\ the\ text\ with\ newlines\ at\ those\ locations.\ Here's\ some\ code\ I\ wrote\ that\ does\ this\ (feel\ free\ to\ suggest\ improvements).\ A\ global\ variable\ \"formawid\"\ is\ set\ to\ hold\ the\ desired\ width\ in\ characters\ of\ the\ wrapped\ text,\ and\ the\ text\ widget\ (here,\ \".tx\")\ is\ configured\ to\ that\ width,\ with\ word\ wrap:\n\n======\n\ .tx\ configure\ -width\ \$formawid\ -wrap\ \$wordwrap\n\ wm\ geometry\ .\ \{\}\ \;\ #\ Make\ sure\ the\ toplevel\ shrinks\ or\ expands\ to\ fit\n======\n\nThen,\ after\ a\ delay\ of\ one-tenth\ of\ a\ second\ (which\ seems\ to\ be\ needed\ for\ some\ reason),\ the\ following\ procedure\ is\ run.\ The\ \"whattodo\"\ arg\ can\ be\ either\ \"print\"\ (to\ prepare\ hard-wrapped\ text\ for\ printing)\ or\ \"show\"\ (to\ display\ hard-wrapped\ text\ in\ the\ text\ widget).\ If\ there\ is\ a\ selection,\ only\ the\ selected\ text\ will\ be\ hard-wrapped\;\ if\ there\ isn't,\ all\ text\ in\ the\ widget\ will\ be\ hard-wrapped.\ \n\n======\nproc\ formanew\ \{whattodo\}\ \{\n\ \ \ \ global\ formawid\n\ \ \ \ #\ Identify\ beginning\ and\ end\ of\ text\ to\ format:\n\ \ \ \ if\ \{\[.tx\ tag\ ranges\ sel\]\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ set\ selon\ 1.0\n\ \ \ \ \ \ \ \ set\ seloff\ \[.tx\ index\ end\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ selon\ \[.tx\ index\ sel.first\]\n\ \ \ \ \ \ \ \ set\ seloff\ \[.tx\ index\ sel.last\]\n\ \ \ \ \}\n\ \ \ \ set\ texin\ \[expr\ int(\$selon)\]\n\ \ \ \ set\ texend\ \[expr\ int(\$seloff)\]\n\ \ \ \ #\ Initialize\ variable\ to\ hold\ output:\n\ \ \ \ set\ formatext\ \"\"\n\ \ \ \ for\ \{set\ i\ \$texin\}\ \{\$i\ <=\ \$texend\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ #\ Get\ text\ to\ newline:\n\ \ \ \ \ \ \ \ set\ endolin\ \[.tx\ index\ \$i.end\]\n\ \ \ \ \ \ \ \ set\ endochar\ \[lindex\ \[split\ \$endolin\ \".\"\]\ end\]\n\ \ \ \ \ \ \ \ set\ whatline\ \[.tx\ get\ \$i.0\ \$endolin\]\n\ \ \ \ \ \ \ \ #\ If\ line\ is\ blank,\ insert\ only\ newline\ into\ output:\n\ \ \ \ \ \ \ \ if\ \{\[string\ trim\ \$whatline\]\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ formatext\ \"\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ If\ not,\ then\ find\ out\ where\ line\ is\ wrapped:\n\ \ \ \ \ \ \ \ for\ \{set\ c\ 1\}\ \{\$c\ <=\ \$endochar\}\ \{incr\ c\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .tx\ see\ \$i.\$c\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ceemin\ \[expr\ \{\$c-1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ boxie\ \[.tx\ get\ \$i.\$ceemin\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Get\ y\ coordinates\ of\ bounding\ boxes\ for\ adjoining\ characters:\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pixy\ \[lindex\ \[.tx\ bbox\ \$i.\$ceemin\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ nexy\ \[lindex\ \[.tx\ bbox\ \$i.\$c\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ y\ coordinate\ of\ bounding\ box\ is\ greater\ than\ for\n\ \ \ \ \ \ \ \ \ \ \ \ #\ preceding\ character,\ line\ has\ been\ wrapped,\ so\n\ \ \ \ \ \ \ \ \ \ \ \ #\ insert\ preceding\ character\ plus\ newline\ into\ output:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$nexy\ >\ \$pixy\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ formatext\ \$boxie\\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ .tx\ see\ \$i.\$c\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Otherwise,\ insert\ only\ the\ preceding\ character:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ formatext\ \$boxie\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Replicate\ existing\ newline\ from\ text\ widget:\n\ \ \ \ \ \ \ \ if\ \{\$i\ <\ \$texend\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ formatext\ \"\\n\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ if\ \{\$whattodo\ eq\ \"print\"\}\ \{\n\ \ \ \ \ \ \ \ return\ \$formatext\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ .tx\ delete\ \$selon\ \$seloff\n\ \ \ \ \ \ \ \ .tx\ insert\ \$selon\ \$formatext\n\ \ \ \ \ \ \ \ .tx\ edit\ separator\n\ \ \ \ \}\n\}\n\nafter\ 100\ formanew\n======\n\n\[hv\]\ If\ you\ want\ to\ format\ the\ lines,\ look\ into\ textutil::adjust.\ It\ can\ do\ left-,\ right-,\ or\ center-justify,\ adjust\ the\ text\ width,\ and\ do\ hyphenation.\n\n**\ Occurrence\ Count\ **\n\n'''Count\ number\ of\ occurrences\ of\ a\ substring'''\ in\ a\ string:\n\n======\nproc\ scount\ \{subs\ string\}\ \{\n\ \ \ \ regsub\ -all\ \$subs\ \$string\ \$subs\ string\n\}\nproc\ scount2\ \{subs\ string\}\ \{\n\ \ \ \ regexp\ -all\ \$subs\ \$string\ \;#\ 8.3\n\}\n======\n\nThe\ latter\ can\ also\ be\ defined\ by\ currying\ (see\ \[Custom\ curry\]):\n\n======\ninterp\ alias\ \{\}\ scount3\ \{\}\ regexp\ -all\n======\n\n\[JH\]\ writes,\ in\ a\ comp.lang.tcl\ thread\ talking\ about\ this\ subject\n======\nproc\ scount4\ \{subs\ string\}\ \{\n\ \ \ \ regexp\ -all\ ***=\$subs\ \$string\n\}\ \n======\n\nand\ \[AM\]\ initially\ proposes:\n======\nproc\ scount5\ \{subs\ string\}\ \{\n\ \ \ \ set\ count\ \[llength\ \[split\ \[string\ map\ \[list\ \$subs\ \\uFFFF\]\ \ \$string\]\ \\uFFFF\]\]\n\ \ \ \ incr\ count\ -1\ \n\}\n======\n\nbut\ that\ doesn't\ make\ use\ of\ \$string,\ so\ something\ is\ missing...\n\nStephane\ A.\ writes:\n======\nproc\ countstrings\ \{data\ search\}\ \{\n\ \ \ \ set\ l\ \[string\ length\ \$search\]\n\ \ \ \ set\ count\ 0\n\ \ \ \ while\ \{\[set\ i\ \[string\ first\ \$search\ \$data\]\]>=0\}\ \{\n\ \ \ \ \ \ \ \ incr\ count\n\ \ \ \ \ \ \ \ incr\ i\ \$l\n\ \ \ \ \ \ \ \ set\ data\ \[string\ range\ \$data\ \$i\ end\]\n\ \ \ \ \}\n\ \ \ \ set\ count\n\}\ \n======\n\n**\ Reverse\ a\ String\ **\n\n======\nproc\ srevert\ \{s\}\ \{join\ \[lreverse\ \[split\ \$s\ \"\"\]\]\ \"\"\}\ \;#RS\n======\n\nwhere\ ''lrevert''\ is\ of\ course\ on\ \[Additional\ list\ functions\]...\n\n''maybe\ it\ used\ to\ be,\ but\ I\ don't\ see\ it\ there\ now.''\ \[RS\]:\ Oops,\ it's\ named\ ''lreverse''\ there\ -\ sorry!\n\n\[WJP\]:\ That's\ because\ ''revert''\ does\ not\ have\ this\ meaning\ in\ English.\ ''revert''\ means\ ''return\ to\ a\ previous\ state''.\n''reverse''\ is\ more\ general\ in\ that\ it\ can\ have\ that\ same\ meaning\ but\ has\ other\ meanings\ including\ ''go\ backwards''\nand\ ''rearrange\ in\ the\ opposite\ orientation''.\n\n\[FW\]\ notes:\ this\ goes\ through\ a\ transitional\ list\ form.\ \ Still\ being\ a\ CPU\ speed\ and\ memory\ junkie,\ I\ feel\ obliged\ to\ correct\ this\ :P\ I'll\ call\ it\ srever''se'':\n======\nproc\ sreverse\ \{s\}\ \{\n\ \ \ \ set\ res\ \"\"\n\ \ \ \ set\ i\ \[string\ length\ \$s\]\n\ \ \ \ while\ \{\$i\ >=\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \"\$res\[string\ index\ \$s\ \[incr\ i\ -1\]\]\"\n\ \ \ \ \}\n\ \ \ \ return\ \$res\n\}\n======\n\[RS\]\ agrees,\ except\ that\ \[append\]\ may\ be\ more\ efficient:\n======\nproc\ srevert\ s\ \{\n\ \ \ \ set\ l\ \[string\ length\ \$s\]\n\ \ \ \ set\ res\ \"\"\n\ \ \ \ while\ \{\$l\}\ \{append\ res\ \[string\ index\ \$s\ \[incr\ l\ -1\]\]\}\n\ \ \ \ set\ res\n\}\n======\n\[LV\]\ notes\ that\ two\ more\ solutions\ recently\ appeared\ on\ comp.lang.tcl:\nThe\ first\ is\ by\ \[Michael\ Schlenker\]:\n======\nproc\ string_reverse\ \{str\}\ \{\n\ \ \ \ set\ rts\ \"\"\n\ \ \ \ for\ \{set\ i\ \[string\ length\ \$str\]\;\ incr\ i\ -1\}\ \{\$i\ >=\ 0\}\ \{incr\ i\ -1\}\ \{\n\ \ \ \ \ \ \ \ append\ rts\ \[string\ index\ \$str\ \$i\]\n\ \ \ \ \}\n\ \ \ \ return\ \$rts\n\}\n======\nand\ the\ second\ by\ \[(R.\ T.\ Wurth\]:\n\n======\nproc\ srev\ s\ \{\n\ \ \ \ return\ \[join\ \[::struct::list\ reverse\ \[split\ \$s\ \{\}\]\]\ \{\}\]\n\}\n======\n\n\[Am\]\ (13\ december\ 2005)\ The\ question\ came\ up\ again\ in\ the\ chatroom\ yesterday,\ and\ I\ decided\ to\ measure\ the\ performance\ of\ various\ alternatives\ ...\ See:\ \[Performance\ of\ string\ reversing\ algorithms\]\n\n**\ Longest\ Common\ Prefix\ **\n\nAlso\ found\ in\ \[textutil%|%tcllib::textutil\]\n\n\[Arjen\ Markus\]\ At\ times\ I\ have\ had\ the\ need\ (not\ too\ urgent\ though)\ of\ a\ function/proc\ to\ determine\ the\ position\ where\ two\ strings\ (or\ lists)\ become\ different:\n\n\ \ \ \"Arjen\ Markus\"\ versus\ \"Arjen\ Marcus\"\ -->\ position:\ 9\n\ \ \ \"Arjen\ Markus\"\ versus\ \"Arjan\ Markus\"\ -->\ position:\ 3\n\n(though\ mostly\ these\ are\ cases\ where\ my\ name\ and\ the\ variations\ that\ I\ commonly\ encounter\ are\ not\ involved)\ -\ \[RS\]:\ That\ would\ be\ the\ length\ of\ the\ common\ prefix\ which\ one\ might\ implement\ like\ this:\n======\nproc\ commonPrefix\ \{a\ b\}\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ foreach\ i\ \[split\ \$a\ \"\"\]\ j\ \[split\ \$b\ \"\"\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\$i==\$j\}\ \{append\ res\ \$i\}\ else\ break\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\n======\n\nHere\ is\ a\ generalized\ version\ that\ takes\ any\ number\ of\ strings\ and\ returns\ the\ prefix\ which\ all\ have\ in\ common:\n\n======\nproc\ longestCommonPrefix\ strings\ \{\n\ \ \ set\ res\ \{\}\n\ \ \ set\ i\ 0\n\ \ \ foreach\ char\ \[split\ \[lindex\ \$strings\ 0\]\ \"\"\]\ \{\n\ \ \ \ \ \ \ foreach\ string\ \[lrange\ \$strings\ 1\ end\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$string\ \$i\]\ !=\ \$char\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$res\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ append\ res\ \$char\n\ \ \ \ \ \ \ incr\ i\n\ \ \ \}\n\ \ \ set\ res\n\}\ \;#\ RS\n======\n\n''\[MGS\]\ \[\[2004/05/13\]\]''\ -\ Here's\ another\ way\ -\ sort\ a\ list\ of\ strings\ and\ then\ compare\ the\ first\ and\ last:\n\n======\nproc\ string:common\ \{string1\ string2\}\ \{\n\ \ \ \ set\ i\ 1\n\ \ \ \ while\ \{\ \[string\ equal\ -length\ \$i\ \$string1\ \$string2\]\ \}\ \{\ incr\ i\ \}\n\ \ \ \ return\ \[string\ range\ \$string1\ 0\ \[expr\ \{\$i-2\}\]\]\n\}\n\nproc\ string:common:list\ \{args\}\ \{\n\ \ \ \ if\ \{\ \[llength\ \$args\]\ <\ 2\ \}\ \{\n\ \ \ \ \ \ \ \ return\ -code\ error\ \"wrong\ #\ args:\ must\ be\ >=\ 2\"\n\ \ \ \ \}\n\ \ \ \ set\ list\ \[lsort\ \$args\]\n\ \ \ \ return\ \[string:common\ \[lindex\ \$list\ 0\]\ \[lindex\ \$list\ end\]\]\n\}\n======\n\n''\[JEC\]\ \[\[2010/03/18\]\]''\ notes\ the\ above\ string:common\ has\ a\ bug\ and\ never\ returns\ on\ identical\ strings.\ \ Even\ when\ fixed\ \ it\ does\ O(n^2)\ comparisons\n\n''\[BBH\]\ \[\[2004/05/13\]\]''\ \ -\ This\ got\ me\ thinking\ that\ RE\ back\ references\ would\ be\ a\ perfect\ fit,\ a\ little\ playing\ &\ it\ turns\ out\ I\ was\ right\ \;)\n\n======\nproc\ prefix\ \{s1\ s2\}\ \{\n\ \ \ \ regexp\ \{^(.*).*\\0\\1\}\ \"\$s1\\0\$s2\"\ all\ pref\n\ \ \ \ return\ \$pref\n\}\n======\n\nand\ easily\ generalized\ for\ multiple\ words\n\n======\nproc\ prefix\ \{str\ args\}\ \{\n\ \ \ \ set\ re\ \{^(.*).*\}\n\ \ \ \ foreach\ s\ \$args\ \{\n\ \ \ \ \ \ \ \ append\ re\ \{\\0\\1.*\}\n\ \ \ \ \ \ \ \ append\ str\ \"\\0\$s\"\n\ \ \ \ \}\n\ \ \ \ regexp\ \$re\ \$str\ all\ pref\n\ \ \ \ return\ \$pref\n\}\n======\n\n\[NEM\]\ 17Mar2005\ -\ Another\ RE\ variation:\n\n======\nproc\ reprefix\ \{str1\ str2\}\ \{\n\ \ \ \ regexp\ -inline\ ^\[join\ \[split\ \$str1\ \"\"\]\ ?\]?\ \$str2\n\}\n======\n\n\[NEM\]\ 5mins\ later.\ 'Tis\ broken:\n\n\ %\ reprefix\ iamadonut\ iamatoilet\n\ iamat\n\nWhoops.\n----\n\n**\ Subscripts\ **\n\nThe\ characters\ for\ which\ subscript\ versions\ exist\ in\ Unicode\ (digits,\ parens,\ some\ operators\ -see\ the\ list\ in\ code)\ are\ converted\ to\ their\ subscripted\ Unicodes.\ Others\ are\ left\ unchanged.\ (For\ superscripts\ the\ positions\ 1,2,3\ seem\ not\ to\ be\ filled\ in\ my\ installation,\ so\ I\ didn't\ add\ the\ corresponding\ code...)\n\n======\nproc\ subscript\ s\ \{\n\ \ \ \ set\ res\ \"\"\n\ \ \ \ foreach\ char\ \[split\ \$s\ \"\"\]\ \{\n\ \ \ \ \ \ \ \ set\ pos\ \[lsearch\ -exact\ \{0\ 1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ +\ -\ =\ (\ )\}\ \$char\]\n\ \ \ \ \ \ \ \ if\ \{\$pos>=0\}\ \{set\ char\ \[format\ %c\ \[incr\ pos\ 0x2080\]\]\}\n\ \ \ \ \ \ \ \ append\ res\ \$char\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n%\ puts\ H\[subscript\ 2\]O\nH?O\n======\n\n**\ Strictly\ a\ Floating\ Point\ Number\ **\n\nthe\ regular\ ''\[string\]\ is\ double''\ term\ fires\ on\ integers\ too.\ The\ following\ fires\ on\ real\ floats\ only:\n======\nproc\ isFloat\ x\ \{expr\ \{\[string\ is\ double\ -strict\ \$x\]\ &&\ !\[string\ is\ int\ \$x\]\}\}\ \;#RS\n======\n\n**\ Sort\ a\ String\ **\n\n\[AM\]\ For\ some\ symbolic\ manipulations\ (w.r.t.\ group\ theory,\ oh\ just\ for\ the\ fun\ of\ it),\ I\ need\ to\ sort\ the\ characters\ in\ a\ string,\ so\ that\ for\ instance\ \"ababa\"\ becomes\ \"aaabb\".\n\nThis\ can\ be\ done\ via:\n\n======\nproc\ charsort\ \{\ string\ \}\ \ \{\n\ \ \ return\ \[join\ \[lsort\ \[split\ \$string\ \{\}\]\ \]\ \{\}\ \]\n\}\n======\n\n**\ Longest\ String\ **\n\nHere's\ a\ little\ proc\ to\ find\ the\ length\ of\ the\ longest\ string\ in\ a\ list:\n\n======\nproc\ maxlen\ \{args\}\ \{\n\ \ \ \ #\ Written\ 2003\ by\ Ed\ Suominen,\ hereby\ placed\ in\ the\ public\ domain\n\ \ \ \ if\ \{\ \[llength\ \$args\]\ >\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ if\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \[set\ x\ \[string\ length\ \[lindex\ \$args\ 0\]\]\]\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \[set\ y\ \[string\ length\ \[lindex\ \$args\ 1\]\]\]\ <\ 0\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -1\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\ \$x\ ==\ \$y\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 1\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x\ \[lsort\ -decreasing\ -command\ maxlen\ \[lindex\ \$args\ 0\]\]\n\ \ \ \ \ \ \ \ return\ \[string\ length\ \[lindex\ \$x\ 0\]\]\n\ \ \ \ \}\n\}\n======\n\nAlternative:\n\n======\nproc\ maxlen\ args\ \{\n\ \ \ \ if\ \{\[llength\ \$args\]==1\}\ \{set\ args\ \[lindex\ \$args\ 0\]\}\n\ \ \ \ set\ res\ \[string\ length\ \[lindex\ \$args\ 0\]\]\n\ \ \ \ foreach\ i\ \[lrange\ \$args\ 1\ end\]\ \{\n\ \ \ \ \ \ \ \ set\ l2\ \[string\ length\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$l2\ >\ \$res\}\ \{set\ res\ \$l2\}\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n======\n\n**\ String\ Insert\ **\n\n'''Insert\ a\ string\ into\ another'''\ at\ a\ given\ position,\ analogous\ to\ \[linsert\]:\n\n======\nproc\ strinsert\ \{string\ pos\ char\}\ \{\n\ \ \ \ set\ original\ \[string\ index\ \$string\ \$pos\]\n\ \ \ \ string\ replace\ \$string\ \$pos\ \$pos\ \$char\$original\n\}\ \;#\ RS\n%\ strinsert\ hello\ 1\ x\nhxello\n======\n\n**\ Substition\ that\ Preserves\ Grouping\ **\n\n\[RHS\]\ ''23Feb2005''\ There\ have\ been\ a\ number\ of\ times\ where\ I\ have\ wanted\ a\ version\ of\ '''subst'''\ that\ preserves\ grouping.\ For\ example,\ I\ want\ to\ be\ able\ to\ do\ the\ following:\n\n======\n%\ array\ set\ myarr\ \[subst\ \{\n\ \ \ \ a\ \$x\n\ \ \ \ b\ \[getConfigValue\ something\]\n\ \ \ \ c\ \{\n\ \ \ \ \ \ \ \ a\ b\n\ \ \ \ \ \ \ \ c\ d\n\ \ \ \ \}\n\}\]\n%\ array\ get\ myArr\na\ 1\ b\ blah\ c\ \{\n\ \ \ \ \ \ \ \ a\ b\n\ \ \ \ \ \ \ \ c\ d\n\ \ \ \ \}\n======\n\nMy\ main\ reason\ for\ this\ is,\ when\ the\ dataset\ get\ large,\ I\ tend\ to\ find\ \\\ line\ continuations\ fairly\ ugly...\ That,\ and\ my\ emacs\ config\ doesn't\ indent\ well\ for\ multiple\ levels\ of\ line\ continuations\ if\ there's\ sub\ levels.\n\nIn\ pursuit\ of\ the\ above,\ I\ came\ up\ with\ the\ following:\n======\nproc\ gsubst\ \{input\}\ \{\n\ \ \ \ set\ data\ \{\}\n\ \ \ \ foreach\ line\ \[split\ \$input\ \\n\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\ \[info\ complete\ \$data\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ data\ \"\ \$line\"\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ data\ \"\\n\$line\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ uplevel\ 1\ list\ \$data\n\}\n======\n\nThe\ above\ proc\ should,\ in\ theory,\ cause\ the\ following\ two\ to\ work\ exactly\ the\ same\n\ list\ a\ 1\ \\\n\ \ \ \ \ \ b\ \$x\ \\\n\ \ \ \ \ \ c\ \{\n\ \ \ \ \ \ \ \ \ \ 1\n\ \ \ \ \ \ \ \ \ \ 2\n\ \ \ \ \ \ \}\ \\\n\ \ \ \ \ \ d\ \[somecommand\]\n\ gsubst\ \{\n\ \ \ \ \ \ a\ 1\n\ \ \ \ \ \ b\ \$x\n\ \ \ \ \ \ c\ \{\n\ \ \ \ \ \ \ \ \ \ 1\n\ \ \ \ \ \ \ \ \ \ 2\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ d\ \[somecommand\]\n\ \}\n----\n\n\[\[What\ should\ the\ category\ be\ for\ this?\]\]\ \[RS\]:\ Hm..\ \"Additional\"?\ That's\ the\ criterion\ I\ quickly\ search\ this\ set\ of\ pages\ with\ -\ such\ takeaway\ snippets\ used\ to\ be\ in\ the\ \[Bag\ of\ algorithms\]\ until\ it\ grew\ too\ thick.\n\n**\ N-th\ Occurrence\ of\ a\ Substring\ **\n\n\[Silas\]\ -\ 2005.10.14\ -\ If\ you\ want\ to\ find\ the\ third\ or\ fourth\ ocurrance\ of\ a\ string\ in\ another\ string,\ you'll\ have\ to\ use\ \[string\ first\]\ many\ times.\ The\ following\ proc\ could\ help:\n\n**\ String\ to\ Proper\ English\ Title\ **\n\n\[D.\ McC\]:\ \ Oct\ 20\ 2005\ -\ The\ \"string\ totitle\"\ subcommand\ only,\ and\ always,\ capitalizes\ the\ first\ letter\ in\ a\ string,\ no\ matter\ how\ many\ words\ are\ in\ the\ string\ or\ what\ the\ words\ are.\ Here's\ some\ code\ to\ convert\ a\ multiple-word\ expression\ in\ English\ to\ a\ properly\ capitalized\ title,\ in\ which\ all\ initial\ letters\ are\ capitalized\ except\ those\ of\ articles,\ conjunctions,\ and\ prepositions\ with\ four\ or\ fewer\ letters.\ '''(Needs\ improvement--see\ revised\ version,\ farther\ below)'''\n\n======\nproc\ title\ \{str\}\ \{\n\ \ \ \ set\ output\ \"\"\n\ \ \ \ set\ nocaps\ \[list\ a\ an\ and\ at\ but\ by\ for\ from\ in\ into\ of\ on\ or\ the\ to\ with\]\n\ \ \ \ foreach\ word\ \[split\ \$str\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\[lsearch\ \$nocaps\ \$word\]\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ totitle\ \$word\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ append\ output\ \"\$word\ \"\n\ \ \ \ \}\n\ \ \ \ return\ \[string\ trim\ \$output\]\n\}\n======\n\nExample:\n\n\ %\ set\ bogomips\ \"groundwork\ of\ the\ metaphysics\ of\ balderdash\"\n\ groundwork\ of\ the\ metaphysics\ of\ balderdash\n\ %\ title\ \$bogomips\n\ Groundwork\ of\ the\ Metaphysics\ of\ Balderdash\n\n\[DKF\]:\ Cool!\ It's\ not\ quite\ right\ though.\ The\ following\ gets\ closer,\ but\ isn't\ right\ yet\ either\ (testing\ on\ your\ paragraph\ above,\ of\ course!)\n======\nproc\ title\ \{str\}\ \{\n\ \ \ \ set\ output\ \"\"\n\ \ \ \ set\ nocaps\ \{a\ an\ and\ at\ but\ by\ for\ from\ in\ into\ of\ on\ or\ the\ to\ with\}\n\ \ \ \ foreach\ word\ \[regexp\ -all\ -inline\ \{\[\\w'.\]+|\\W+\}\ \$str\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \{\[A-Za-z\]*\}\ \$word\]\ &&\ \[lsearch\ \$nocaps\ \$word\]\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ In\ 8.5\ should\ use\ the\ 'ni'\ operator\ instead\ of\ the\ \[lsearch\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ totitle\ \$word\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ append\ output\ \$word\n\ \ \ \ \}\n\ \ \ \ return\ \[string\ trim\ \$output\]\n\}\n======\n\n\[LES\]\ You\ forget\ that\ you'll\ want\ those\ \"nocaps\"\ words\ to\ be\ turned\ to\ title\ if\ they\ begin\ a\ sentence.\ Here\ is\ a\ proc\ I\ use\ to\ rename\ files\ (usually\ mp3).\ It\ doesn't\ handle\ punctuation,\ but\ handles\ hyphens,\ e.g.:\ \"Artist\ -\ A\ Song\ Title\".\ Tweaking\ it\ to\ also\ take\ punctuation\ (periods\ or\ first\ word\ of\ title)\ in\ consideration\ should\ be\ trivial.\ That\ is\ not\ desired\ in\ file\ renaming\ because\ periods\ (dots)\ do\ not\ mean\ the\ same\ as\ in\ regular\ titles.\n\n======\nproc\ mp3\ args\ \ \{\n\ \ \ \ set\ _nocaps\ \{\n\ \ \ \ \ \ \ \ a\ as\ à\ às\ ao\ aos\ de\ da\ das\ do\ dos\ e\ em\ na\ nas\ no\ nos\ \n\ \ \ \ \ \ \ \ o\ os\ ou\ para\ por\ que\ sem\ sob\n\ \ \ \ \ \ \ \ an\ and\ are\ at\ but\ for\ from\ if\ in\ is\ it's\ not\ of\ on\ or\ \n\ \ \ \ \ \ \ \ the\ to\ under\ vs\ vs.\ with\ without\n\ \ \ \ \ \ \ \ au\ aux\ avec\ dans\ des\ en\ et\ le\ la\ les\ ou\ par\ pour\ qui\ si\n\ \ \ \ \ \ \ \ con\ del\ el\ en\ la\ las\ los\ sin\ y\n\ \ \ \ \}\;\ #\ German\ and\ Italian,\ anyone?\n\ \n\ \ \ \ foreach\ _file\ \[\ glob\ *\ \]\ \{\ \n\ \ \ \ \ \ \ \ if\ \{\ \$_file\ eq\ \{.:\}\ \}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ #\ lowercase\ the\ whole\ name\n\ \ \ \ \ \ \ \ set\ _old\ \ \$_file\n\ \ \ \ \ \ \ \ set\ _file\ \[string\ tolower\ \$_file\]\n\ \ \ \ \ \ \ \ set\ _new\ \{\}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \;#\ empty\ _new\ in\ each\ iteration\n\ \ \ \ \ \ \ \ set\ _c\ \ \ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \;#\ zero\ counter\ in\ each\ iteration\n\ \n\ \ \ \ \ \ \ \ foreach\ _word\ \$_file\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ incr\ _c\n\ \n\ \ \ \ \ \ \ \ \ \ \ \ #\ anything\ right\ after\ \"\ -\ \"\ probably\ is\ the\ first\ word\ of\ a\ phrase.\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ current\ word\ is\ \"-\",\ reset\ counter\ so\ next\ word\ is\ 1\ and\ gets\ caps\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \$_word\ eq\ \"-\"\ \}\ \{\ set\ _c\ 0\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ current\ word\ is\ 1,\ it\ gets\ caps\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \$_c\ ==\ 1\ \}\ \{\ set\ _word\ \[string\ totitle\ \$_word\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ it\ is\ not\ in\ exceptions,\ it\ gets\ caps\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \[lsearch\ \$_nocaps\ \$k\ \]\ <\ 0\ \}\ \ \ \ \ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ k\ \[string\ totitle\ \$k\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ add\ the\ word\ to\ the\ new\ name\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ _new\ \$k\n\ \ \ \ \ \ \ \ \}\n\ \n\ \ \ \ \ \ \ \ #\ UNCOMMENT\ the\ two\ next\ lines\ if\ you\ want\ files\ renamed\ automatically\n\ \ \ \ \ \ \ \ #file\ rename\ \ \$_old\ \ RENAME_TEMP\n\ \ \ \ \ \ \ \ #file\ rename\ \ RENAME_TEMP\ \ \$_new\n\ \ \ \ \ \ \ \ puts\ \ \"\$_old\\n\$_new\\n\"\n\ \ \ \ \}\n\}\n======\n\n\[D.\ McC\]:\ \ OK,\ I\ do\ want\ the\ \"nocaps\"\ words\ capitalized\ if\ they\ (1)\ begin\ the\ title\ or\ (2)\ come\ right\ after\ a\ colon.\ Also,\ as\ I\ belatedly\ noticed,\ quotation\ marks\ need\ to\ be\ stripped\ out\ for\ \"string\ totitle\"\ to\ work\ right,\ but\ then\ put\ back\ into\ the\ finished\ product.\ I'd\ go\ a\ long\ way\ to\ avoid\ a\ regular\ expression\ like\ \{\[\\w'.\]+|\\W+\},\ though.\ Let's\ try\ this:\n\n======\nproc\ title\ \{str\}\ \{\n\ \ \ \ set\ output\ \"\"\n\ \ \ \ set\ nocaps\ \[list\ a\ an\ and\ at\ but\ by\ for\ from\ in\ into\ of\ on\ or\ the\ to\ with\]\n\ \ \ \ set\ count\ 0\n\ \ \ \ foreach\ word\ \[split\ \$str\]\ \{\n\ \ \ \ \ \ \ \ #\ Strip\ quotation\ marks:\n\ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$word\ 0\]\ ==\ \"\\\"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ quote\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ trim\ \$word\ \\\"\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ quote\ 0\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Always\ capitalize\ the\ first\ word\;\ otherwise,\n\ \ \ \ \ \ \ \ #\ don't\ capitalize\ any\ words\ in\ the\ \"nocaps\"\ list:\n\ \ \ \ \ \ \ \ if\ \{\$count\ ==\ 0\ ||\ \[lsearch\ \$nocaps\ \$word\]\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ totitle\ \$word\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Add\ word\ plus\ space,\ with\ or\ without\ quotation\ marks,\ to\ output:\n\ \ \ \ \ \ \ \ if\ \{\$quote\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ output\ \"\\\"\$word\\\"\ \"\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ output\ \"\$word\ \"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Capitalize\ any\ word\ after\ a\ colon:\n\ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$word\ end\]\ ==\ \":\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ count\ 0\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ count\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \[string\ trim\ \$output\]\n\}\n======\n\nExample:\n\n\ %\ set\ wordsworth\ \{what\ I\ say\ is:\ by\ gum,\ give\ me\ the\ finest\ \"bogomips\"\ in\ the\ universe!\}\n\ what\ I\ say\ is:\ by\ gum,\ give\ me\ the\ finest\ \"bogomips\"\ in\ the\ universe!\n\ %\ title\ \$wordsworth\n\ What\ I\ Say\ Is:\ By\ Gum,\ Give\ Me\ the\ Finest\ \"Bogomips\"\ in\ the\ Universe!\n\n======\nproc\ mystringFirst\ \{substring\ mystring\ ocorrencia\}\ \{\n\ \ \ \ if\ \{!\$ocorrencia\}\ \{return\ -1\}\n\ \ \ \ set\ index\ 0\n\ \ \n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$ocorrencia\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ index\ \[string\ first\ \$substring\ \$mystring\]\n\ \ \ \ \ \ \ \ set\ mystring\ \[string\ range\ \$mystring\ \[expr\ \$index\ +\ 1\]\ \[string\ length\ \$mystring\]\]\n\ \ \ \ \}\n\ \ \n\ \ \ \ return\ \$index\n\}\n======\n#\ Here's\ an\ example\ that\ doesn't\ use\ foreach.\n\nproc\ title-case\ \{text\}\ \{\n\ \ \ \ for\ \{set\ index\ 0\}\ \{\$index\ <\ \[string\ length\ \$text\]\}\ \{incr\ index\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\ \[string\ wordstart\ \$text\ \$index\]\ ==\ \$index\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[string\ replace\ \$text\ \$index\ \$index\ \[string\ toupper\ \[string\ index\ \$text\ \$index\]\]\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[string\ replace\ \$text\ \$index\ \$index\ \[string\ tolower\ \[string\ index\ \$text\ \$index\]\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$text\n\}\n======\n**\ Misc\ **\n\nLV:\ Take\ a\ look\ at\ \[Tcl-FAQ\]'s\ part\ 5\ to\ gather\ ideas\ on\ other\npackages\ with\ string\ functions.\n\n----\n\n'''Letterspacing:'''\ spreading\ a\ string\ by\ inserting\ blanks\ between\ each\ two\ characters.\ \[KBK\]\ notes\ that\ there's\ a\ printer's\ proverb:\ Anyone\ who\ would\ l\ e\ t\ t\ e\ r\ s\ p\ a\ c\ e\ \ \ \ l\ o\ w\ e\ r\ c\ a\ s\ e\ \ \ would\ steal\ sheep.\ Simply\ functional:\n======\nproc\ letterspace\ s\ \{join\ \[split\ \$s\ \"\"\]\ \"\ \"\}\ \;#\ RS\n%\ letterspace\ \"steal\ sheep\"\ns\ t\ e\ a\ l\ \ \ s\ h\ e\ e\ p\n======\n\nIn\ the\ book\ ''Stop\ Stealing\ Sheep\ &\ find\ out\ how\ type\ works,''\ by\ Erik\ Spiekermann\ and\ E.M.\ Ginger,\nAdobe\ Press,\ 1993,\ on\ page\ 7,\ in\ the\ side\ bar\ the\ quotation\ attributed\ to\ Frederic\ Goudy\ was,\n\"Anyone\ who\ would\ letterspace\ black\ letter\ would\ steal\ sheep.\"\ --\ \[escargo\]\n\n\n<<categories>>\ Category\ Discussion\ |\ Category\ Example\ |\ Category\ String\ Processing} CALL {my revision {Additional string functions}} CALL {::oo::Obj6562559 process revision/Additional+string+functions} CALL {::oo::Obj6562557 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4