Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

tcl equivalent of perl "chop"

1,810 views
Skip to first unread message

Mahurshi Akilla

unread,
Apr 9, 2008, 12:57:01 PM4/9/08
to
Is there an equivalent tcl command to perl's "chop" ?

I would like to delete out the last character (not necessarily new
line) off of a string. Is there an easy way to do this "chop" in
tcl?

Thanks

Donald G Porter

unread,
Apr 9, 2008, 1:05:52 PM4/9/08
to
Mahurshi Akilla wrote:
> I would like to delete out the last character (not necessarily new
> line) off of a string.

% string replace foo end end
fo

--
| Don Porter Mathematical and Computational Sciences Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|______________________________________________________________________|

EL

unread,
Apr 9, 2008, 1:07:03 PM4/9/08
to
Mahurshi Akilla schrieb:

> I would like to delete out the last character (not necessarily new
> line) off of a string. Is there an easy way to do this "chop" in
> tcl?

set v [string range $v 0 end-1]

> Thanks

At your pleasure ;-).


Eckhard

vit...@gmail.com

unread,
Apr 9, 2008, 2:19:39 PM4/9/08
to
Actually, this one is the true "chop" clone:

string trim string ?chars?
Returns a value equal to string except that any leading or
trailing characters from the set given by chars are removed. If chars
is not specified then white space is removed (spaces, tabs, newlines,
and carriage returns).

string trimleft string ?chars?
Returns a value equal to string except that any leading characters
from the set given by chars are removed. If chars is not specified
then white space is removed (spaces, tabs, newlines, and carriage
returns).

string trimright string ?chars?
Returns a value equal to string except that any trailing
characters from the set given by chars are removed. If chars is not
specified then white space is removed (spaces, tabs, newlines, and
carriage returns).

Bezoar

unread,
Apr 9, 2008, 2:50:30 PM4/9/08
to

I notice that you say "Not necessarily a newline" does this mean you
wish to
keep a newline and then delete the next non-newline character? Perls
chop does
not do this as it just remove the last character regardless of what it
is. I have
coded up this chop procedure to take a list of ignorable characters.
The ignored
characters are added back to the return string by default. By default
it will not
ignore characters(as the ignorechar list is empty) and it will not
remove any that
it has skipped over. Also this because I used the "in" operator this
is Tcl8.5; but
can be easily converted to 8.4 using lsearch.

proc chop { s { ignorechars {}} { truncate 0 } } {
set idx 0
set postbuff ""
while { [string index $s end-$idx ] in $ignorechars } {
set postbuff "[string index $s end-$idx ]$postbuff"
incr idx;
}
incr idx
if { $truncate } {
return [string range $s 0 end-$idx ]
}
return "[string range $s 0 end-$idx ]$postbuff"
}

set test { "" "this is a test\n" "this is a testttt\n" "thirst" "t"
"this is a test\n\n\n" "this is a tes\nt\n\n" }

set testnum 0
foreach tstr $test {
puts " ignore newline and t \"$tstr\" =>\"[chop $tstr { "\n"
"t" } ]\""
puts " ignore newline and t truncated \"$tstr\" =>\"[chop $tstr
{ "\n" "t" } 1 ]\""
puts " ignore nothing \"$tstr\" =>\"[chop $tstr {} ]\" "
puts " ignore nothing truncated \"$tstr\" =>\"[chop $tstr {} 1 ]
\" "

}


HTH Carl

Gerald W. Lester

unread,
Apr 9, 2008, 3:29:21 PM4/9/08
to
Here is a shorter (and loopless) version of your chop:

proc chop {s {ignorechars {}} {truncate 0}} {

set tmp [string trimright $s $ignorechars]
set idx [string length $tmp]
set postbuff [string range $s $idx end]
set tmp [string range $tmp 0 end-1]
if {!$truncate} then {
append tmp $postbuff
}
return $tmp
}


--
+--------------------------------+---------------------------------------+
| Gerald W. Lester |
|"The man who fights for his ideals is the man who is alive." - Cervantes|
+------------------------------------------------------------------------+

Glenn Jackman

unread,
Apr 9, 2008, 3:42:37 PM4/9/08
to
At 2008-04-09 02:19PM, "vit...@gmail.com" wrote:
> Actually, this one is the true "chop" clone:
> string trim string ?chars?
[...]

No. Perl's chop removes the last character, period. [string trim] and
friends remove (by default) all trailing whitespace. The [string range]
and [string replace] solutions are correct.

--
Glenn Jackman
"If there is anything the nonconformist hates worse than a conformist,
it's another nonconformist who doesn't conform to the prevailing
standard of nonconformity." -- Bill Vaughan

Donald G Porter

unread,
Apr 9, 2008, 3:44:21 PM4/9/08
to
Glenn Jackman wrote:
> No. Perl's chop removes the last character, period.

Are we sure it's really the last character, or is it the last byte?

bill...@alum.mit.edu

unread,
Apr 9, 2008, 5:12:47 PM4/9/08
to
On Apr 9, 12:44 pm, Donald G Porter <d...@nist.gov> wrote:
> Glenn Jackman wrote:
> > No. Perl's chop removes the last character, period.
>
> Are we sure it's really the last character, or is it the last byte?

Yes, it is the last character, not byte. Run:

my $a = "\x{0061}\x{00e9}";
print $a;
chop($a);
print $a;

The result is a - lower case e with acute accent - a,
showing that the chop removes the accented e, which is two bytes.

andy...@gmail.com

unread,
Mar 28, 2018, 6:52:46 PM3/28/18
to
Hi All,

like Mahurshi and I looked for perl chop & read all replies.

For example: if I want to write a round_up function by chopping ONE CHARACTER AT A TIME (w/o knowing what is that character) via a loop to see if < or >= 5, then round up the post-choped #. this process repeats until met the desired number of digits from user (and this # of digits can be changed randomly).

* w/ string strimright, if I specify all ?0123456789?, it'll remove all the decimals at one path (which is not what I want)

* w/ the string range ... I'm a tcl beginner, I couldn't get it work, :).

* I think I can split the string then use lindex to chop one char at a time via a loop. Since this is just writing for fun, I stop for now, :).

Thanks, Andy.

Rich

unread,
Mar 28, 2018, 7:29:06 PM3/28/18
to
andy...@gmail.com wrote:
> On Wednesday, April 9, 2008 at 9:57:01 AM UTC-7, Mahurshi Akilla wrote:
>> Is there an equivalent tcl command to perl's "chop" ?
>>
>> I would like to delete out the last character (not necessarily new
>> line) off of a string. Is there an easy way to do this "chop" in
>> tcl?
>
> * w/ the string range ... I'm a tcl beginner, I couldn't get it work, :).

set chopped [string range $input 0 end-1]

andy...@gmail.com

unread,
Mar 29, 2018, 1:59:42 PM3/29/18
to
On Wednesday, April 9, 2008 at 9:57:01 AM UTC-7, Mahurshi Akilla wrote:
Thanks Rich,

your suggestion returns the remain string (after chopped), please see the output below. How do I get the char got chopped (not the remain string).

set i 3; #chop to 3 decimal for Ex.
set n_dec 3425094
set n_j [string length $n_dec]
puts "n_dec = $n_dec"

for {set j $i} {$j < $n_j} {incr j} {
set c [string range $n_dec 0 end-1]
puts "j=$j c = $c"
}

Output: round_up.tcl
n_dec = 3425094
j=3 c = 342509
j=4 c = 342509
j=5 c = 342509
j=6 c = 342509

_/ so I updated the n_dec after chopped:

for {set j $i} {$j < $n_j} {incr j} {
set c [string range $n_dec 0 end-1]
set n_dec $c
puts "j=$j c = $c"
}

Output: round_up.tcl
n_dec = 3425094
j=3 c = 342509
j=4 c = 34250
j=5 c = 3425
j=6 c = 342

Rich

unread,
Mar 29, 2018, 2:10:01 PM3/29/18
to
andy...@gmail.com wrote:
> On Wednesday, April 9, 2008 at 9:57:01 AM UTC-7, Mahurshi Akilla wrote:
>> Is there an equivalent tcl command to perl's "chop" ?
>>
>> I would like to delete out the last character (not necessarily new
>> line) off of a string. Is there an easy way to do this "chop" in
>> tcl?
>>
>> Thanks
>
> Thanks Rich,
>
> your suggestion returns the remain string (after chopped), please see
> the output below. How do I get the char got chopped (not the remain
> string).

My memory of perl was that chop() removed the last character and
returned all but the last character, and you did not get to see what was
chopped. What I gave you did the same in Tcl. But it has also been a
long time since I wrote any Perl so things may have changed there in
the interim.

But if you wanted the character that got chopped, one way would be to
do two calls:

# first, you'd 'index' the last character and extract it
set char_that_gets_chopped [string range $input end end]

# then you'd 'index all but the last, and extract it
set chopped_string [string range $input 0 end-1]

But if what you really want to do is iterate the characters of the
string in reverse order, this is likely a better way:

foreach char [lreverse [split $input ""]] {
# do something with char
}


If you want the tail char and the rest all in one call, that should
work with a regex:

regexp {(.*)(.)$} $input -> rest tail

Whether running a regex is too much load for your use is a question
only you can answer.

Rich

unread,
Mar 29, 2018, 2:16:17 PM3/29/18
to
andy...@gmail.com wrote:
> Output: round_up.tcl

Also, you might find it to be really useful to tell us *exactly what it
is you want to do* (note: not what steps you take or think you should
take, but the real root thing you are trying).

Your filename above implies you want to do some form of decimal number
rounding.

If so, there is likely a much better way than chopping characters.

Andy N.

unread,
Mar 29, 2018, 2:22:11 PM3/29/18
to
On Wednesday, April 9, 2008 at 9:57:01 AM UTC-7, Mahurshi Akilla wrote:
Thank Rich for super fast reply,

[string range $str end end] works as I would like to. I updated the code to:

for {set j $i} {$j < $n_j} {incr j} {
set c [string range $n_dec end end]
set n_dec [string range $n_dec 0 end-1]
puts "j=$j n_dec=$n_dec c = $c"
}

Output: round_up.tcl
n_dec = 3425094
j=3 n_dec=342509 c = 4
j=4 n_dec=34250 c = 9
j=5 n_dec=3425 c = 0
j=6 n_dec=342 c = 5

Thanks again.

Donald Arseneau

unread,
Mar 30, 2018, 12:07:55 AM3/30/18
to
andy...@gmail.com writes:

> For example: if I want to write a round_up function by chopping ONE CHARACTER AT A TIME (w/o knowing what is that character) via a loop to see if < or >= 5, then round up the post-choped #. this process repeats until met the desired number of digits from user (and this # of digits can be changed randomly).

I couldn't follow the details of that description exactly. If this is
sort-of a game for experimenting with and learning Tcl, then great.
Just don't use such an algorithm for actually rounding numbers! It is
terribly inefficient, and it appears to be wrong! (As I read it, you
would round 1.444445 [or equivalent] up to 2.)

> * I think I can split the string then use lindex to chop one char at a time via a loop. Since this is just writing for fun, I stop for now, :).


Yes! That loop would look like:

foreach d [lreverse [split $value {}]] {


--
Donald Arseneau as...@triumf.ca
Message has been deleted

Andy N.

unread,
Mar 30, 2018, 4:43:27 PM3/30/18
to
Thanks Rich & Donald,

I only experiment tcl, :).

Rich makes me realizing an interesting point about perl chop can do 3 things:

1) it actually chopped the string (that is why Rich recall it returns the remain string) and 2) return the chopped char at the same time.

$c = chop ($any_str) : do both. or

chop ($any_str) : still do both (we ignore the returned char)


3) if the string is omitted, it works w/ the default string: $_ .For Ex:

$c = chop () or

chop ()


I try to write a tcl proc chop for experimenting like:


proc chop {} {
variable gstr
set c [string range $gstr end end]
set gstr [string range $gstr 0 end-1]
return $c
}

set gstr "aaa bbb"

puts "Before: gstr = $gstr"
set xc [chop]
puts " After: gstr = $gstr xc = $xc"

_/ Output: chop.tcl
Before: gstr = aaa bbb
After: gstr = aaa bb xc = b


It works like 3) above which updated the default-str (gstr) and returned the chopped-char (xc).

_/ Is there a way to make it works like perl: if I pass in a string, it works w/ that string [does both 1) and 2)] if I omitted, it worked w/ some default-str name [does same 1) and 2)]?

Thanks,

Brad Lanam

unread,
Mar 30, 2018, 4:53:00 PM3/30/18
to
On Friday, March 30, 2018 at 1:43:27 PM UTC-7, Andy N. wrote:
> I try to write a tcl proc chop for experimenting like:
>
>
> proc chop {} {
> variable gstr
> set c [string range $gstr end end]
> set gstr [string range $gstr 0 end-1]
> return $c
> }
>
> set gstr "aaa bbb"
>
> puts "Before: gstr = $gstr"
> set xc [chop]
> puts " After: gstr = $gstr xc = $xc"
>
> _/ Output: chop.tcl
> Before: gstr = aaa bbb
> After: gstr = aaa bb xc = b
>
>
> It works like 3) above which updated the default-str (gstr) and returned the chopped-char (xc).
>
> _/ Is there a way to make it works like perl: if I pass in a string, it works w/ that string [does both 1) and 2)] if I omitted, it worked w/ some default-str name [does same 1) and 2)]?
>
> Thanks,

Sure (not implementing a default string -- that's perl 4-ish and that's
not really recommended).

proc chop { gstrv } {
upvar $gstrv gstr

set c [string range $gstr end end]
set gstr [string range $gstr 0 end-1]
return $c
}

set gstr "aaa bbb"

puts "Before: gstr = $gstr"
set xc [chop gstr]

Rich

unread,
Mar 30, 2018, 5:32:41 PM3/30/18
to
Andy N. <andy...@gmail.com> wrote:
> _/ Is there a way to make it works like perl: if I pass in a string,
> it works w/ that string [does both 1) and 2)] if I omitted, it worked
> w/ some default-str name [does same 1) and 2)]?

Yes, in a way, but you will have some messy programming to emulate
*all* of what you described for Perl's chop:

And, for 'with string', you want both the remainder and the chop char
returned?

proc chop {args} {
switch -exact -- [llength $args] {
0 { # use a 'default name' (note, not actually a good idea, but..., use _ to match Perl)
upvar 1 _ thestring
}
1 {
upvar 1 [lindex $args 0] thestring
}
default {
error "Invalid number of arguments to chop: ([llength $args]) '$args'"
}
}
# You could add a check on the length of $thestring here and possibly
# do something different if it is < 2 chars long
return [list [string range $thestring 0 end-1] [string range $thestring end end]]
}

Andy N.

unread,
Mar 30, 2018, 5:37:34 PM3/30/18
to
Thanks Brad,

I can live w/o the default-str.

Best regards,
Andy.

Andy N.

unread,
Mar 30, 2018, 5:41:01 PM3/30/18
to
Thank Rich for a very detailed and advance tcl for me to learn,
Andy.

Rich

unread,
Mar 30, 2018, 5:49:57 PM3/30/18
to
Andy N. <andy...@gmail.com> wrote:
> Thank Rich for a very detailed and advance tcl for me to learn,
> Andy.
>

Note, you are using google groups, and you keep replying to the top
level message, which *completely messes up threading* of the replies.

Best: Don't *ever* use google groups to post to usenet. Instead get a
real news reader:
https://en.wikipedia.org/wiki/List_of_Usenet_newsreaders

And use either Eternal September (https://www.eternal-september.org/)
or AIOE (https://news.aioe.org/) to post.

Ok: Make sure you are replying to the actual message to which you are
responding, not simply replying to the whole thread at once.


Second, when you do post, *always* quote a bit of the prior context to
which you are replying, that way each article is somewhat standalone
(which is how the articles are meant to be read, google f****** that up
with their awful web interface).

0 new messages