cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
593
Views
1
Helpful
6
Replies

EEM: parse a string one character at a time

6502
Level 1
Level 1

I need to calculate a simple hash from a string of characters (containing no whitespace).  I can't figure out the regexp I need to use in the below "action foreach" statement to parse the string charcter by character:

event manager applet test1
event none
action 0100 set range "gig1/0/1-2"
action 0110 set csum "0"
action 0120 foreach char "$range" "\C"
action 0130 add $csum $char
action 0140 set csum "$_result"
action 0150 end
action 0160 divide $csum 255
action 0170 set csum "$_remainder"
action 0180 puts "CSUM = $csum"
 

Any ideas?

1 Accepted Solution

Accepted Solutions

6502
Level 1
Level 1

Far too much fun.  Might as well be programming in assembly language.  Not that there's anything wrong with that.

event manager environment CHARMAP , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > \077 @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z


event manager applet test4
event none
action 100 set range "gig1/0/1-2"
action 110 set csum1 "0"
action 120 set csum2 "0"
action 130 set checksum "0"
action 140 set index "0"
action 150 set char ""
action 160 set map_char ""
action 170 string length "$range"
action 180 set length "$_string_result"
action 190 while $index lt $length
action 200 regexp "^." "$range" char
action 210 puts "$char"
action 220 set index1 "44"
action 230 foreach map_char "$CHARMAP" " "
action 240 if $char eq "$map_char"
action 250 increment csum1 $index1
action 260 divide $csum1 255
action 270 set csum1 "$_remainder"
action 280 increment csum2 $csum1
action 290 divide $csum2 255
action 300 set csum2 "$_remainder"
action 310 break
action 320 end
action 330 increment index1 1
action 340 end
action 350 string trimleft "$range" "$char"
action 360 set range "$_string_result"
action 370 increment index 1
action 380 end
action 390 increment checksum $csum2
action 400 multiply $checksum 256
action 410 set checksum $_result
action 420 increment checksum $csum1
action 430 puts "Checksum = $checksum"

View solution in original post

6 Replies 6

M02@rt37
VIP
VIP

hello @6502 

The "foreach" construct is not directly designed to iterate over characters in a string. Instead, it is primarily used to iterate over elements in a list. However, you can achieve your goal by using a combination of other actions.

event manager applet test1
event none
action 0100 set range "gig1/0/1-2"
action 0110 set csum 0

# Loop through each character in the string
action 0120 for each i in "$range" {
action 0130 set char [string index "$range" $i]

# Convert the character to ASCII and add it to the checksum
action 0140 set ascii_val [scan $char "%c"]
action 0150 math add csum $ascii_val
action 0160 }

# Output the checksum
action 0170 puts "CSUM = $csum"

Best regards
.ı|ı.ı|ı. If This Helps, Please Rate .ı|ı.ı|ı.

Dan Frey
Cisco Employee
Cisco Employee

Foreach loop iterates over each word so the number of words and spaces is known.   string length is sum of the string (all char and spaces) then arithmetic to subtract the spaces from string length.

event manager applet test
 event none
 action 010 set mystring "learning to count with eem 1 2 3"
 action 014 set num "-1"
 action 020 foreach word "$mystring"
 action 030  add $num 1
 action 035  set num "$_result"
 action 040 end
 action 100 string length "$mystring"
 action 110 subtract $_string_result $_result
 action 120 puts "$_result characters in mystring"
 action 200 puts "$num spaces in mystring"

INET#event manager run test
25 characters in mystring
7 spaces in mystring

6502
Level 1
Level 1

Thanks M02@rt37 for the algorithm, but unfortunately those string operators don't appear to exist in EEM, or at least in a way that i can use them with local applet variables.  Here's what I came up with that could work, using "action regexp", if I could only figure out the right search string to use:

...

action 150 while $index lt $length
action 160 regexp "/^.{$index}[:word:]/" "$range" char
action 180 puts "$char"
action 190 increment index 1
action 200 increment csum $char
action 210 end

The goal of the regexp search string is to return the single character within $range at position $index and assign it to $char.

6502
Level 1
Level 1

OK, figured out how to parse the string character by character:

event manager applet test4
event none
action 100 set range "gig1/0/1-2"
action 110 set csum "0"
action 120 set index "0"
action 130 set char ""
action 140 string length "$range"
action 150 set length "$_string_result"
action 160 while $index lt $length
action 170 regexp "^." "$range" char
action 180 puts "$char"
action 190 increment index 1
action 200 add $csum $char
action 201 set csum "_$result"
action 210 string trimleft "$range" "$char"
action 220 set range "$_string_result"
action 230 end
action 240 divide $csum 255
action 250 set csum "$_remainder"
action 260 puts "CSUM = $csum"

But as was aluded to earlier by M02@rt37 , the add action in line 200 fails becuase $char contains a alpha character instead of a number.  Since there doesn't seem to be any typing in eem scripts, I was hoping that it would just force the alpha into a number , but sadlly no.  Is there any way to easily convert the alpha into a number?  It doesn't necessarily have to be the ASCII value.  I guess I could use a loop similar to the above to iterate through a list of "abcde..xyz0123...9-/" and use the loop index when the match occurs as the "number", but this is already getting too ugly...

Dan Frey
Cisco Employee
Cisco Employee

Are you looking for the ascii number for each character to perform the divide function and get the remainder?  If so you will need EEM/TCL for this.   Below is using the tcl shell for testing and can be written in EEM TCL if this meets your need.

INET#tclsh
INET(tcl)#set data "gig1/0/1-2"
gig1/0/1-2
INET(tcl)#set num 0
0
INET(tcl)#foreach char [split $data ""] {
+>    set output [scan $char %c]
+>    set sum [expr $output + $num]
+>    puts $sum
+>    set num $sum
+>}
103
208
311
360
407
455
502
551
596
646

INET(tcl)#set result [expr $num % 255]
136

 

6502
Level 1
Level 1

Far too much fun.  Might as well be programming in assembly language.  Not that there's anything wrong with that.

event manager environment CHARMAP , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > \077 @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z


event manager applet test4
event none
action 100 set range "gig1/0/1-2"
action 110 set csum1 "0"
action 120 set csum2 "0"
action 130 set checksum "0"
action 140 set index "0"
action 150 set char ""
action 160 set map_char ""
action 170 string length "$range"
action 180 set length "$_string_result"
action 190 while $index lt $length
action 200 regexp "^." "$range" char
action 210 puts "$char"
action 220 set index1 "44"
action 230 foreach map_char "$CHARMAP" " "
action 240 if $char eq "$map_char"
action 250 increment csum1 $index1
action 260 divide $csum1 255
action 270 set csum1 "$_remainder"
action 280 increment csum2 $csum1
action 290 divide $csum2 255
action 300 set csum2 "$_remainder"
action 310 break
action 320 end
action 330 increment index1 1
action 340 end
action 350 string trimleft "$range" "$char"
action 360 set range "$_string_result"
action 370 increment index 1
action 380 end
action 390 increment checksum $csum2
action 400 multiply $checksum 256
action 410 set checksum $_result
action 420 increment checksum $csum1
action 430 puts "Checksum = $checksum"