So I need to get the Caesar Cipher code in smalltalk and create a method and use it so I can do the following test on it
|aString|
aString:=Caesar new encrypt: 'CAESAR'.
Transcript show: aString.
I already have the class made. But I need to make the method of it.
I found this but how can I make a method out of this so I can all the above code in playground.
| i c strCipherText strText iShiftValue iShift |
strText := 'the quick brown fox jumps over the lazy dog'.
iShiftValue := 3.
strCipherText := ''.
iShift := iShiftValue \\ 26.
i := 1.
[ i <= (strText size) ]
whileTrue: [
c := (strText at: i) asUppercase.
( ( c >= $A) & ( c <= $Z ) )
ifTrue: [
((c asciiValue) + iShift > $Z asciiValue)
ifTrue: [
strCipherText := strCipherText, (((c asciiValue) + iShift - 26)
asCharacter asString).
]
ifFalse: [
strCipherText := strCipherText, (((c asciiValue) + iShift)
asCharacter asString).
].
]
ifFalse: [
strCipherText := strCipherText, ' '.
].
i := i + 1.
].
Transcript show: strCipherText.
Transcript cr.
So to make thing clear, I need to make a method using the Caesar Cipher code and use the "aString" code at the beginning and test it with that. I have this code above but this has already text in it and can't be put into the method.
Any help will be appreciated.
As Max said in his comment the code above can be put in a method. The only missing part is a first line with the selector and the formal argument:
caesarCipherOf: strText
<insert the code here>
Another good suggestion by Max is to call the argument aString rather than strText because that's more aligned with how Smalltalkers name things.
But now let's take a look at the source code itself:
The comparison c >= $A & (c <= $Z) means c isLetter.
The conditional calculation of the next character means that we want to shift-rotate c by moving it 3 characters to the right, wrapping it around if it gets beyond $Z. This can be easily expressed as:
(c codePoint - 64 + 3 \\ 26 + 64) asCharacter
where 64 = $A codePoint - 1, is the offset between $A and any given uppercase character c. Note also that I've replaced asciiValue with codePoint.
With these two observations the method can be re-written as
caesarCipherOf: aString
^aString collect: [:c |
c isLetter
ifTrue: [(c asUppercase codePoint - 64 + 3 \\ 26 + 64) asCharacter]
ifFalse: [$ ]]
This is not only shorter, it is more efficient because it avoids creating two new instances of String at every character. Specifically, any expression of the form
string := string , <character> asString
creates two Strings: one as the result of sending #asString, another as the result of sending the concatenation message #,. Instead, #collect: creates only one instance, the one that the method returns.
Related
I know blocks can be passed and used in that way.
But is there any way to call a block, just by having a block? Something like this?
aBlock := [ ... ].
aBlock run.
I tried searching for the BlockClosure class in the System browser, but couldn't find it.
Yes! And in fact, you can do pretty interesting things with them, like activating them within themselves. For example, this block computes factorial recursively calling itself:
factorialBlock := [:n |
n <= 1
ifTrue: [n]
ifFalse: [n * (factorialBlock value: n - 1)]
]
and to try it:
factorialBlock value: 5
That would not be an example of a very good coding practice, but it is of the power of block closures!
Let's add that besides value, if your block has arguments, you can also use
[:f | <do something with f>] value: a
where f is a formal argument (an unbound variable name) and a is an actual object that will bind to f when #value: is sent.
For two arguments use value:value: and for many valueWithArguments:, which receives an Array.
Examples
[:x | x squared - 1] value: 3
-> 3 squared - 1 (i.e., 8)
[:x :y | x + 2 / (y - 4)] value: 2 value: 0
-> 2 + 2 / (0 - 4) (i.e., -1)
Exercise
What's the result of evaluating the following?:
block := [:x | x value: 2].
block value: [:y | y + 1]
Yes it can. Also, you send the message 'value' to it to evaluate the block, not 'run'. In fact, you do not have to assign it to a variable. You can just do this:
[ ... ] value.
Check this one:
Lambda Calculus in Pharo
Yes, the Y Combinator is useful in normal programs
https://medium.com/concerning-pharo/lambda-calculus-in-pharo-a4a571869594#.2a78xp31s
From the article:
ycombinator := [ :f |
[ :g | g value: g ] value: [ :g |
f value: [ :x |
(g value: g) value: x ] ] ]
The force is strong in this one.
I have been trying to find a way to remap my keyboard and send 5-digit hex unicode chars, the method described here: ahk Send only supports 4-digit hex codes {U+nnnn}, I know that in the past, autohotkey didnt support unicode natively so it was needed some functions in order to do that, maybe thats the solution for me.
Example:
#If GetKeyState("CapsLock","T")
+u::Send {U+1D4B0}
The results from that is 풰 instead of 𝒰, and the code for 풰 is {U+D4B0}, meaning AHK is reading only the last 4 digits. How can I fix it even if I need to make new functions to achieve that?
Thanks
-Mark
Unicode values larger than 0xFFFF must be encoded as two surrogate pairs:
+u:: SendInput ,{U+D835}{U+DCB0}
Here is the algorithm to convert a Unicode code point that is in range 0x10000 to 0x10FFFF, to surrogate pairs, paraphrased from wikipedia:
First subtract 0x10000 from the code point, to get a number in range 0xFFFFF.
Then right shift the number by 10 bits and add 0xD800 to it to get the high surrogate.
Take the lowest ten bits of the number and add 0xDC00 to it to get the low surrogate
I took 2501's solution from above and turned it into working a working ahk script. I have been searching on and off for this solution for months!
+u:: FUNC_SEND_UNICODE( 0x1D4B0 )
FUNC_SEND_UNICODE(func_args)
{
/*
;commented out proof of concept code:
str := ""
u1 := Chr( 0xD835 )
u2 := Chr( 0xDCB0 )
str := u1 . u2
bk := clipboard
clipboard := str
send, ^v
sleep,200
clipboard := bk
*/
;bk == "clipboard [B]ac[K]up
bk := clipboard
;chunk of data that needs to be cut into
;two chunks.
ful := func_args + 0
/* commented out testing code, using original
sample input of stack overflow post
;msgbox,ful:[%ful%]
;for testing. Expecting input to be equal to
;the value in the post.
if(ful != 0x1D4B0 ){
msgbox,"[WHATTHEHECK]"
}
*/
;Subtract 0x10000 from ful, gets number
;in range(rng) 0x0 to 0xFFFFFF inclusive
rng := ful - 0x10000
if(rng > 0xFFFFF)
{
msgBox,[Step1 Resulted In Out Of Range]
}
;Do shifting and masking, then check to make
;sure the value is in the expected range:
big_shif := (rng >> 10)
lit_mask := (rng & 0x3FF)
if(big_shif > 0x3FF)
{
msgBox,[MATH_ERROR:big_shif]
}
if(lit_mask > 0x3FF)
{
msgBox,[MATH_ERROR:lit_mask]
}
big := big_shif + 0xD800
lit := lit_mask + 0xDC00
if(big < 0xD800 || big >= 0xDBFF){
msgBox, [HIGH_SURROGATE_OUT_OF_BOUNDS]
}
if(lit < 0xDC00 || lit >= 0xDFFF){
msgBox, [LOW_SURROGATE_OUT_OF_BOUNDS]
}
;Convert code points to actual characters:
u1 := Chr( big )
u2 := Chr( lit )
;concatentate those two characters to
;create our final surrogate output:
str := u1 . u2
;set it equal to clipboard, and send
;the clipboard. This is a hack.
;send,%str% works fine in google chrome,
;but fails in notepad++ for some reason.
;tried appending EOF, STX, ETX control codes
;along with output, but to no effect.
clipboard := str
send, ^v
;Must sleep before restoring clipboard,
;otherwise, the clipboard will get
;overwritten before ctrl+v has the chance
;to output the character. You'll end up just
;pasting whatever was originally on the
;clipboard.
sleep,200
clipboard := bk
return
}
An implementation of 2501's answer.
Listens for ;u
Followed by an ending character (e.g. ; or Return)
Waits for a sequence of keypresses like 1D4B0
Input ends when terminated by a ;
Sends the desired Unicode character directly if below 65536, calculates surrogate pairs otherwise
Inserts the desired Unicode character
:?:`;u::
Input, keys, , `;
if (StrLen(keys) < 5)
Send {U+%keys%}
else {
keys := "0x" + keys
num := keys - 0x10000
w1 := Format("{:x}", (num >> 10) + 0xD800)
w2 := Format("{:x}", (num & 1023) + 0xDC00)
Send {U+%w1%}{U+%w2%}
}
return
For reference:
Hotstrings
Input
StrLen
Casting string to numeric
Format
Bitwise operations
Send
From somewhere on the internet: sendunicodechar(0x1D4B0)
SendUnicodeChar(charCode)
{
VarSetCapacity(ki, 28 * 2, 0)
EncodeInteger(&ki + 0, 1)
EncodeInteger(&ki + 6, charCode)
EncodeInteger(&ki + 8, 4)
EncodeInteger(&ki +28, 1)
EncodeInteger(&ki +34, charCode)
EncodeInteger(&ki +36, 4|2)
DllCall("SendInput", "UInt", 2, "UInt", &ki, "Int", 28)
}
EncodeInteger(ref, val)
{
DllCall("ntdll\RtlFillMemoryUlong", "Uint", ref, "Uint", 4, "Uint", val)
}
edit. probably got downvoted bc of missing source. I simply dont know where I got it from anymore. But when I used it a few years ago, it worked flawlessly.
I'm currently working on an assignment done in smalltalk and while I'm just getting the grasp of the language, I'm a bit stumped and am looking for some direction.
Normally to print to the transcript in Pharo I would use:
print
Transcript show: 'Hello my name is: ' , self theName printString; cr
It seems that if I put a conditional in the beginning such as
printNew
(age < 50) ifTrue: [ Transcript show: 'Hello my name is: ', self theName, 'and I am old' printString ]; cr
I can't seem to get the printNew method to print to the transcript. Thank you in advance!
Let me format your expression to better understand it:
(age < 50)
ifTrue: [
Transcript show:
'Hello my name is: ', self theName, 'and I am old' printString];
cr
looks like
(age < 5) ifTrue: [<something>]; cr
which in turn has the structure of
(age < 5) msg; cr
because in Smalltalk ifTrue: [<something>] is nothing but a message. Do you see the mistake now? The cascade symbol ; sends first msg to the Boolean expression (age < 5) and then sends it cr which it does not understand. Just fix the transposition between ] and ; cr:
(age < 50)
ifTrue: [
Transcript show:
'Hello my name is: ', self theName, 'and I am old' printString;
cr]
Note also that a better way to write the same is
(age < 50)
ifTrue: [
Transcript
show: 'Hello my name is: ';
show: self theName;
show: ' and I am old' printString;
cr]
Why? Because this way you do not create two intermediate strings by concatenating the three parts of your text.
Finally note that because of precedence rules you don't need the parentheses around age < 50
BTW, if you are under 50 you are not old!
I want to define block and call it in this way:
add := [ :a :b |
^(a+b).
].
n := add value: 1 value: 2.
But when I try it, I get an error:
$ gst 3.1.st
Object: 3 error: return from a dead method context
SystemExceptions.BadReturn(Exception)>>signal (ExcHandling.st:254)
SystemExceptions.BadReturn class(Exception class)>>signal (ExcHandling.st:151)
SmallInteger(Object)>>badReturnError (Object.st:1389)
UndefinedObject>>executeStatements (3.1.st:3)
How can I call a function in GNU Smalltalk?
Well, I dropped the return statement, and this code works fine. But when I try to define more complicated function, for example:
nod := [ :a :b |
(a=b) ifTrue: [a].
(a>b) ifTrue: [nod value: (a-b) value: b].
(a<b) ifTrue: [nod value: a value: (b-a)].
].
n := nod value: 1 value: 2.
n printNl.
It prints nil. And if I define with "early exit":
nod := [ :a :b |
(a=b) ifTrue: [^a].
(a>b) ifTrue: [nod value: (a-b) value: b].
(a<b) ifTrue: [nod value: a value: (b-a)].
].
n := nod value: 1 value: 2.
n printNl.
It gives me the same error: return from a dead method context.
I solve this problem in this way:
nod := [ :a :b |
(a=b) ifTrue: [
a
] ifFalse: [
(a>b) ifTrue: [nod value: (a-b) value: b] ifFalse: [nod value: a value: (b-a)].
]
].
n := nod value: 1 value: 2.
n printNl.
But I think, it is not beautiful way.
Drop the return statement (^) from your code and it will work fine.
In smalltalk, returning exits the method in which the return statement appears. It's used for early exits, for example a < b ifTrue: [^a] ifFalse:[^b].
In this case, you don't want the block to exit the containing method, you just want it to evaluate to something when sending it value:value:. A block evaluates to the last statement in it, so just make it a regular statement there and it will do the trick.
The error message you got, by the way, also explains the problem: you're trying to return 3 from a method which is already dead.
Remove non-local return (^), parenthesis, and period inside a block. And try doing it again.
You've already accepted an answer to your original question, then redefined your question.
To answer your updated question, you could use the fact that a block returns the value of its last statement, and use a local variable:
nod := [ :a :b | |r|
(a = b) ifTrue: [r := a].
(a > b) ifTrue: [r := nod value: (a-b) value: b].
(a < b) ifTrue: [r := nod value: a value: (b-a)].
r
].
I am curious, though, about the context. I suspect this might more appropriately be defined as a selector/method for a class.
By the way, the above implementation will go into an infinite recursion if either argument is negative.
The simplest way to get the results you're after would be:
nod := [ :a :b | a gcd: b ].
:)
I'm trying to go though a array and add characters from that array to another object. The problem is I keep getting a error "Instances of character are not indexable". However when I run tag := tag,char outside of the do block then it works.
|data startTag tag|.
data := '123456778'
startTag := false.
tag := ''.
data asArray do: [:char |
tag := tag,char]
The , is defined as
Collection>>, aCollection
^self copy addAll: aCollection; yourself
so that tries to operate on your single character as if it were a collection. That explains the error.
For larger collections you do not want to build up using , because of the copy that happens each time. Therefore use the streaming protocol:
|data tag|
data := '123456778'.
tag := String streamContents: [:s |
data do: [ :char |
s nextPut: char]]
Also take a look at Collection>>do:separatedBy: to add separators between your data.
[edit] Ah, ok, that's something like
|data tag tags state|
data := '<html>bla 12 <h1/></html>'.
state := #outside.
tags := OrderedCollection new.
tag := ''.
data do: [ :char |
state = #outside ifTrue: [
char = $< ifTrue: [
state := #inside.
tag := '' ]]
ifFalse: [
char = $> ifTrue: [
state := #outside.
tags add: tag]
ifFalse: [ tag := tag, (char asString)]]].
tags
"an OrderedCollection('html' 'h1/' '/html')"