Expecco Code Snippets/en
Inhaltsverzeichnis
- 1 Working with Code
- 2 Code Snippets for Common Tasks
- 2.1 Input and Output Pins
- 2.2 Bits & Bytes
- 2.3 Numeric
- 2.4 Number Vectors
- 2.5 SI Units and Physical Values
- 2.6 Converting Numbers to Strings and Vice Versa
- 2.7 Comparing Strings containing Numbers (String to Numberverctor)
- 2.7.1 Subproblem1: splitting a longer string into parts
- 2.7.2 Subproblem2: reading a number from a string
- 2.7.3 Getting a collection of numbers
- 2.7.4 Solution
- 2.7.5 Comparing the size of the two number vectors
- 2.7.6 Alternative (if the number of values is fix)
- 2.7.7 Finding the first difference between 2 vectors
- 2.7.8 Finding the longest common prefix of 2 vectors
- 2.7.9 Alternative using Streams
- 2.8 String/Text Processing
- 2.9 Searching/Extracting Parts from a Document
- 2.10 File I/O
- 2.11 Sockets
- 2.12 HTML
- 2.13 XML
- 2.14 JSON
Working with Code[Bearbeiten]
Before going into concrete details, you should learn to use the tools MethodFinder, Workspace and SystemBrowser.
The MethodFinder lets you find methods (i.e. virtual functions) by entering arguments and a desired result. For example, to convert 'abc' into 'ABC' the MethodFinder wil tell you that the function named "asUppercase" will do that.
A Workspace lets you enter a piece of code and execute it, for example, entering the text " 'abc' asUppercase ", selectingthat piece of code and using the menu function "printIt" will execute the code and paste the result at the cursor position.
Finally, a SystemBrowser shows the concrete implementation (i.e. the source code) of the underlying system functions. If you use the menu function "Implementors", you can search for the "asUppercase" function and see its implementation(s). Most functions also provide examples near the bottom of the source code, which can be selected and executed pretty much like in a Workspace.
Code Snippets for Common Tasks[Bearbeiten]
Warning: this page is for geeks, programmers and coding freaks
This page is for coders of elementary actions which are to execute inside expecco (i.e. Smalltalk and JavaScript elementary actions). For bridged actions, the corresponding programming language/environment determines the syntax and set of possible operations and is outside the control of expecco.
You will find code snippets for common tasks here. Although most (or all) could also be implemented using existing actions from the standard library, it is often more convenient to write a little elementary action eg. to extract data from received binary messages or from a textual document.
You can copy-paste these snippets into the code editor and modify as appropriate. You can also paste them into a Workspace window and execute them there. Finally, you may also find those snippets via the Method Finder, when entering the desired result value.
Input and Output Pins[Bearbeiten]
To read a value from a pin named inPinName, use:
Smalltalk (see more here):
|x| x := inPinName value.
JavaScript and NodeJS:
var x; x = inPinName.value();
Object x; x = inPinName.value();
x = inPinName.value()
C:
long l = longValue(inPinName); char* s = stringValue(inPinName); float f = floatValue(inPinName); double d = doubleValue(inPinName); unsigned char* b = bytesValue(inPinName);
To write a value x to an output pin named outPinName, use:
Smalltalk:
outPinName value: x.
JavaScript, NodeJS and Groovy:
outPinName.value(x);
Python:
outPinName.value(x)
C:
putLong(outPinName, l); // l has long or int type putString(outPinName, s); // s has char* type (0-terminated) putStringN(outPinName, s, n); // s has char* type (n chars sent to pin) putFloat(outPinName, f); putDouble(outPinName, d); putBytesN(outPinName,b, n); // n bytes sent to pin
Bits & Bytes[Bearbeiten]
Set, Clear or Toggle a Bit[Bearbeiten]
Smalltalk:
|numIn result| numIn := 0b10011001. "/ using masks result := numIn bitOr: 0b00110000. "/ to set the two bits result := numIn bitAnd: 0b11110000. "/ to mask bits result := numIn bitClear: 0b00000011. "/ to clear bits result := numIn bitXor: 0b00001100. "/ to toggle bits result := numIn bitTest: 0b00001100. "/ to test if masked bits are all set result := numIn lowBits: 5. "/ to extract a number of lowBits "/ using bit numbers (index starts with 1 for the least significant bit) result := numIn bitAt: 1. "/ to extract the first bit result := numIn setBit: 2. "/ set the second bit result := numIn clearBit: 2. "/ clear the second bit result := numIn invertBit: 2. "/ toggle the second bit
JavaScript:
var numIn, result; numIn = 0b10011001; // using masks result = numIn | 0b00110000; // to set the two bits result = numIn & 0b11110000; // to mask bits result = numIn & ˜0b00000011; // to clear bits result = numIn ^ 0b00001100; // to toggle bits result = (numIn & 0b00001100) != 0; // to test if masked bits are all set result = numIn.lowBits(5); // to extract a number of lowBits // using bit numbers (index starts with 1 for the least significant bit) result = numIn.bitAt(1); // to extract the first bit result = numIn.setBit(2); // set the second bit result = numIn.clearBit(2); // clear the second bit result = numIn.invertBit(2); // toggle the second bit
Counting, Highest and Lowest Bit[Bearbeiten]
Smalltalk:
|numIn result| numIn := 0b10011001. result := numIn highBit. "/ index of highest bit result := numIn lowBit. "/ index of lowest bit result := numIn bitCount. "/ count ones
JavaScript:
var numIn, result; numIn = 0b10011001; result = numIn.highBit(); // index of highest bit result = numIn.lowBit(); // index of lowest bit result = numIn.bitCount(); // count ones
Shifting and Byte Access[Bearbeiten]
Smalltalk:
|numIn result| numIn := 0xABCD. result := numIn bitShift: 8. "/ left shift by 8 result := numIn bitShift: -8. "/ right shift by 8 result := numIn << 8. "/ alternative left shift result := numIn >> 8. "/ alternative right shift result := numIn digitByteAt:1. "/ the lowest 8 bits result := numIn digitByteAt:2. "/ the next 8 bits result := numIn digitBytes. "/ bytes as ByteArray
JavaScript:
var numIn, result; numIn = 0xABCD; result = numIn << 8; // left shift by 8 result = numIn >> 8; // right shift by 8 result = numIn.digitByteAt(1); // as above
Accessing Bytes/Ints/Floats in a ByteArray[Bearbeiten]
Typical tasks when receiving binary encoded communication protocol messages are to extract bytes, ints, floats and strings.
Smalltalk:
|bytes result| "/ constant byte array here; "/ could also come from a file, stream, message or document (see below) bytes := #[ 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 ]. result := bytes at:1. "/ 1 based index here result := bytes[1]. "/ alternative syntax; also 1 based result := bytes signedInt16At:2. "/ signed int16 in machine's native byte order result := bytes signedInt16At:3 MSB:false. "/ in explicit lsb-order result := bytes signedInt16At:3 MSB:true. "/ in explicit msb-order result := bytes signedInt32At:2. "/ same options as above result := bytes signedInt64At:2. "/ same options as above result := bytes signedInt128At:1. "/ same options as above result := bytes unsignedInt16At:2. "/ same for unsigned ints result := bytes unsignedInt16At:3 MSB:false. result := bytes unsignedInt16At:3 MSB:true. result := bytes unsignedInt32At:2. result := bytes unsignedInt64At:2. "/ writing into a byte array bytes int16At:4 put:0x1234. "/ again in native byte order bytes int16At:4 put:0x1234 MSB:true. "/ or explicit order "/ floats and doubles result := bytes floatAt:4. "/ extract a 32bit float result := bytes floatAt:4 MSB:true "/ in given byte order result := bytes doubleAt:4. "/ extract a 64bit float result := bytes doubleAt:4 MSB:true "/ in given byte order bytes floatAt:4 put:1.234. "/ encode a 32bit float (native byte order) bytes floatAt:4 put:1.234 MSB:true. "/ encode a 32bit float MSB bytes doubleAt:4 put:1.234. "/ encode a 64bit float (native byte order) "/ strings result := bytes stringAt:2 size:4. "/ extract bytes as a string result := bytes zeroByteStringAt:3 maximumSize:3 "/ extract from a 0-terminated C-string
JavaScript:
var bytes, result; // constant byte array here; // could also come from a file, stream, message or document (see below) bytes = [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 ].asByteArray(); result = bytes[1]; // 1 based index here result = bytes.signedInt16At(2); // signed int16 in machine's native byte order result = bytes.signedInt16At_MSB(3, false); // in explicit lsb-order result = bytes.signedInt16At_MSB(3, true); // in explicit msb-order result = bytes.signedInt32At(2); // same options as above result = bytes.signedInt64At(2); // same options as above result = bytes.signedInt128At(1); // same options as above result = bytes.unsignedInt16At(2); // same for unsigned ints result = bytes.unsignedInt16At_MSB(3,false); result = bytes.unsignedInt16At_MSB(3,true); result = bytes.unsignedInt32At(2); result = bytes.unsignedInt64At(2); // writing into a byte array bytes.int16At_put(4,0x1234); // again in native byte order bytes.int16At_put_MSB(4,0x1234,true); // or explicit order // floats and doubles result = bytes.floatAt(4); // extract a 32bit float result = bytes.floatAt_MSB(4,true); // in given byte order result = bytes.doubleAt(4); // extract a 64bit float result = bytes.doubleAt_MSB(4,true); // in given byte order bytes.floatAt_put(4, 1.234); // encode a 32bit float in native byte order bytes.floatAt_put_MSB(4, 1.234, true); // encode a 32bit float in MSB bytes.doubleAt_put(4, 1.234); // encode a 64bit float // strings result = bytes.stringAt_size(2,4); // extract bytes as a string result = bytes.zeroByteStringAt_maximumSize(3,3); // extract from a 0-terminated C-string
Byte Order and Sign Extension[Bearbeiten]
Smalltak:
rslt := numberIn byteSwapped. "/ swap pairwise rslt := numberIn byteSwapped16. "/ only the lowest 2 bytes rslt := numberIn byteSwapped32. "/ only the lowest 4 bytes rslt := numberIn byteSwapped64. "/ only the lowest 8 bytes rslt := numberIn signExtendedByteValue. "/ sign extent from bit 8 rslt := numberIn signExtendedShortValue. "/ sign extent from bit 16 rslt := numberIn signExtended24BitValue. "/ sign extent from bit 24 rslt := numberIn signExtendedLongValue. "/ sign extent from bit 32
Numeric[Bearbeiten]
Smalltalk:
numberIn sin. "/ sine; also cos, tan, sin, cosh, arcSin, arcCos etc. "/ (all trigonometric args in radians) numberIn degreesToRadians sin "/ converting degrees first n sqrt "/ square root n cbrt "/ cubic root n nthRoot:5 "/ fifth root n ln "/ natural logarithm n log "/ decimal logarithm n log2 "/ binary logarithm n raisedTo:e "/ raised to the power n ** e "/ alternative n1 agm: n2 "/ arithmetic-geometric mean n1 min: n2 "/ the minimum (smaller) of the two n1 max: n2 "/ the maximum
JavaScript:
numberIn.sin(); // similar Math.sin(numberIn); // alternative numberIn.degreesToRadians().sin(); n.sqrt(); n.cbrt(); n.ln(); n.log(); n.log2();
n ** e // raised to the power n.raisedTo(e) // alternative n1.agm(n2); // geometric mean Math.min(n1. n2) // minimum Math.max(n1, n2) // maximum
Number Vectors[Bearbeiten]
v := #f32( 1.0 2.0 3.0 ). "/ a float32 (ieee single) vector "/ (elements must be constant) v := #f64( 1.0 2.0 3.0 ). "/ a float64 (ieee double) vector v min. "/ min and max values v max. v minMax. "/ both as 2-element array v sum. "/ sum and product of elements v product. v arithmeticMean. "/ statistic functions v geometricMean. v harmonicMean. v median. v standardDeviation. v variance.
SI Units and Physical Values[Bearbeiten]
Smalltalk:
1 kilo "/ multiplied by 1000 1 deci "/ divided by 10 1 mega / giga / tera "/ various SI multipliers 1 milli / micro / nano / pico "/ 1 meter "/ physical length 1 kilo meter 1 milli meter 1 ohm / volt / ampere / newton / watt. "/ various physical units 10 milli volt / 1 kilo ohm "/ computing with units (results is ampere) 10 degreesCelsius asFahrenheit 40 degreesFahrenheit asCelsius 100 centi meter asInches
JavaScript:
1.deci().meter() 10.milli().volt() / 1.kilo().ohm() "/ as above
Converting Numbers to Strings and Vice Versa[Bearbeiten]
Smalltalk:
num printString "/ number to string (decimal) num printStringRadix:2 "/ number to string (binary) num printStringRadix:16 "/ number to string (hex) num printStringRadix:16 leftPaddedTo:5 with:$0. "/ left padded string '%3d %02x' printf:{num1 . num2}. "/ C-printf like formatting e'the result is: {3*num1}' "/ string with embedded expression Integer readFrom:'1234' "/ string to number Integer readFrom:s radix:16. "/ hex '%d %02x' scanf: '1234 AF' "/ C-scanf like reading (returns an array)
Comparing Strings containing Numbers (String to Numberverctor)[Bearbeiten]
Given two strings ("string1" and "string2") which contain numbers in ascii:
string1 := '-150.00, 27.18, 2.50, 60.20, 112.82, 19.00'. string2 := '-150, 27.18, 2.5, 60.2, 112.82, 19'.
Use "=" to see if strings or collections are different:
string1 = string2 ifTrue:[ ... ] ifFalse:[ ... ].
The above has the disadvantage, that it requires the two strings to be exactly the same, including the same number of spaces in between numbers and also the same number of decimal digits.
In general, a more intelligent algorithm is needed:
- split each string into a collection of substrings, separated by (in this case) comma characters - convert each such substring into a number - compare the two collections which now contain numbers
Subproblem1: splitting a longer string into parts[Bearbeiten]
To split a string into a collection of substrings (separated by commas):
string splitBy: $,
or assuming that more than one separator character is to be handled:
string splitByAny: ',;'
Subproblem2: reading a number from a string[Bearbeiten]
To convert a string to a number:
string asNumber
Notice, that this will convert the string '19' into an integer and '19.0' into a float. This is usually not a problem, as the integer 19 will compare equal against the float 19.0 as true.
Getting a collection of numbers[Bearbeiten]
Thus, to convert one string into an array of numbers, first split, then collect the results from converting each:
subStrings1 := string1 splitBy: $, . numbers1 := subStrings1 collect:[:eachPart | eachPart asNumber ].
or, in one line:
( string1 splitBy: $, ) collect:[:eachPart | eachPart asNumber ].
Then compare the collections (each now containing numbers).
Solution[Bearbeiten]
So the final solution to our problem is:
numbers1 := ( string1 splitBy: $, ) collect:[:eachPart | eachPart asNumber ]. numbers2 := ( string2 splitBy: $, ) collect:[:eachPart | eachPart asNumber ]. numbers1 = numbers2 ifFalse:[ ... ] ifTrue:[ ... ].
Comparing the size of the two number vectors[Bearbeiten]
You might want to check for the same number of values:
numbers1 size = nubers2 size ifFalse:[ ... ].
Alternative (if the number of values is fix)[Bearbeiten]
If your lines all have the same fix number of values, you can also use scanf, as in:
numbers1 := '%f, %f, %f, %f, %f, %f' scanf:string1. numbers2 := '%f, %f, %f, %f, %f, %f' scanf:string2.
numbers1 = numbers2 ifTrue:[ ... ].
Finding the first difference between 2 vectors[Bearbeiten]
To find the first different value:
index := numbers1 with:numbers2 findFirst:[:nr1 :nr2 | nr1 ~= nr2]. index = 0 ifTrue:[ ... "all equal" ] ifFalse:[ ... "first different at index" ]
Finding the longest common prefix of 2 vectors[Bearbeiten]
samePrefix := numbers1 commonPrefixWith: numbers2
Alternative using Streams[Bearbeiten]
We can also open streams on each string and read numbers pairwise. The following code is somewhat longer:
- verifies that the numbers are readable (i.e. no invalid stuff in the string) - provides the index of the first different value
indexOfFirstDifference := nil. sameNumberOfValues := true. stream1 := string1 readStream. stream2 := string2 readStream. runIndex := 1. [:break | [stream1 atEnd] whileFalse:[ |nr1 nr2| stream2 atEnd ifTrue:[ sameNumberOfValues := false. break value. ]. nr1 := Number readFrom:stream1 onError:[ self error:'invalid nr in stream1' ]. nr2 := Number readFrom:stream2 onError:[ self error:'invalid nr in stream2' ]. nr1 = nr2 ifFalse:[ indexOfFirstDifference := runIndex. break value. ]. runIndex := runIndex + 1. stream1 skipThrough:$,. stream2 skipThrough:$,. ]. sameNumberOfValues := stream2 atEnd. ] valueWithExit. sameNumberOfValues ifFalse:[ ... "not same number of values" ] ifTrue:[ indexOfFirstDifference isNil ifFalse:[ ... "different value detected" ] ifTrue:[ ... "ok" ] ]
String/Text Processing[Bearbeiten]
Searching[Bearbeiten]
Smalltalk:
|s| s := 'some String with multiple Words'. s includes:$S "/ is character included? s includesString:'WITH' "/ no - case difference s includesString:'WITH' caseSensitive:false. "/ yes s indexOf:$S. "/ find index of character (1 based) s indexOfString:'Wo'. "/ find index of substring s indexOfString:'WO' caseSensitive:false. "/ case insensitive s lastIndexOf:$e. "/ find last index of character "/ and similar for string and last string s indexOf:$e startingAt:5 "/ start search at index "/ and similar for string and last string s includesAny:'abc' "/ any of those characters included? s indexOfAny:'abc' "/ index of any of those characters included? s indexOfSeparator "/ first whitespace s lastIndexOfSeparator "/ last whitespace
Splitting / Truncating[Bearbeiten]
s asCollectionOfWords "/ split into words s splitOn:Character space "/ ditto s splitOn:[:ch | ch isUppercase]. "/ split with rule s withoutSeparators "/ trim whitespace at both ends s withoutLeadingSeparators "/ at one end s withoutTrailingSeparators
JavaScript:
var s = "some String with multiple Words"; s.splitOn($' '); s.splitOn(function (ch) { return ch.isUppercase(); })
Searching/Extracting Parts from a Document[Bearbeiten]
|s lines| s := someFile asFilename contentsAsString. "/ read a file into a string s := someFile asFilename contents. "/ read as collection of lines lines := s asCollectionOfLines. "/ convert string to a list of lines lines findFirst:[:l | l startsWith:'foo']. "/ search for a line; return the index lines detect:[:l | l startsWith:'foo']. "/ search but retrieve the line lines count:[:l | l endsWith:'foo']. "/ count lines for which lines select:[:l | l includesString:'foo'] "/ extract only those lines lines copyTo:100 "/ the first 100 lines lines copyLast:100 "/ the last 100 lines lines copyFrom:2 to:10. "/ some of those lines lines copyFrom:2 butLast:10. "/ trim off some at either end lines copyFrom:(lines findFirst:...) "/ search and copy from found lines select:[:l | l matchesRegex: '[0-9]+ [0-9]+' ]. "/ extract lines matching regex pattern lines select:[:l | l matches: '[0-9]+*' ]. "/ extract lines matching GLOB pattern
File I/O[Bearbeiten]
Opening a file, reading, closing[Bearbeiten]
Smalltalk:
|inStream line| inStream := 'foo/bar' asFilename readStream. [inStream atEnd] whileFalse:[ "/ lines, words, strings line := inStream nextLine. "/ one line char := inStream next. "/ one character more := inStream next:10. "/ 10 characters word := inStream nextAlphanumericWord. "/ one word some := inStream upToAll:':'. "/ up to but excluding separator some := inStream throughAll:':'. "/ up to and including separator
"/ binary data byte := inStream nextByte. "/ one byte short := inStream nextUnsignedInt16MSB:false. "/ a short in LSB order short := inStream nextSignedInt16MSB:false. "/ a signed short in LSB order ]. inStream close.
to get the whole contents as one big string:
'foo/bar' asFilename contentsAsString
to get it as a collection of lines:
'foo/bar' asFilename contents
to get it as one big binary ByteArray:
'foo/bar' asFilename binaryContents
it is good practice to ensure that the file is closed:
inStream := 'foo/bar' asFilename open. [ ... ] ensure:[ inStream close ]
which is done by the convenient helper:
'foo/bar' asFilename readingFileDo:[:inStream | [inStream atEnd] whileFalse:[ ... ] ].
JavaScript:
var inStream, line; inStream = "foo/bar".asFilename().readStream(); while (! inStream.atEnd() ) { line = inStream.nextLine(); } inStream.close();
get the whole contents as one big string:
"foo/bar".asFilename().contentsAsString();
get it as a collection of lines:
"foo/bar".asFilename().contents();
get it as one big binary ByteArray:
"foo/bar".asFilename().binaryContents();
using the convenient helper:
"foo/bar".asFilename().readingFileDo( function (inStream) { while (! in stream.atEnd()) { ... } });
Sockets[Bearbeiten]
Sockets inherit from Stream, thus all of the next / nextLine / nextPut / nextPutLine operations can be used on sockets as well.
Connecting, sending, receiving, closing[Bearbeiten]
Smalltalk:
|sock| sock := Socket connectTo:hostname port:portNr. in := sock nextLine. sock nextPutLine:'some message for you'. sock nextPutByte:123. "/ binary data sock nextBytes:100. "/ read binary data sock close
Providing a service[Bearbeiten]
|listenSocket connection| listenSocket := Socket new. listenSocket listenFor:1. [serving] whileTrue:[ connection := listenSocket accept. "/ fork a handler thread for this connection [ [connection atEnd] whileFalse:[ connection nextLine. connection nextPutLine:'hello'. ... ]. connection close. ] forkNamed:'server process' ].
HTML[Bearbeiten]
Parsing[Bearbeiten]
parse an HTML string, to get a DOM (Document Object Model) node:
domNode := HTML::HTMLParser parseText:aString
ask a node for its tag, attributes or children:
domNode tag domNode attributes domNode children
enumerate the children (all of them, recursive):
domNode allChildrenDo: [:eachChild | ... ]
xpath-like access:
domNode / 'tagName' retrieve a set of immediate children with matching tag domNode // 'tagName' retrieve a set of any child with matching tag (recursive)
Example:[Bearbeiten]
|dom nodes firstAnchor| dom := HTML::HTMLParser parseText:'<html><body><a href="http://foo">bla</a>some text</body></html>'. t := dom tag. "/ t now: 'html' nodes := dom // 'a'. "/ nodes now: a collection containing the anchor DOM node firstAnchor := nodes first. firstAnchor href. "/ generates 'http://foo'
XML[Bearbeiten]
Parsing[Bearbeiten]
parse an XML string, to get a DOM (Document Object Model) node:
domNode := XML::XMLParser parse:aString
parse an XML file, to get a DOM node (in expecco 22.1):
domNode := XML::XMLParser parseFile: aFilename
ask a node for its tag, attributes or children:
domNode tag domNode attributes domNode children
enumerate the children (all of them, recursive):
domNode allChildrenDo: [:eachChild | ... ]
xpath-like access:
domNode / 'tagName' retrieve a set of immediate children with matching tag domNode // 'tagName' retrieve a set of any child with matching tag (recursive)
Example:[Bearbeiten]
|doc nodes firstBla secondBla| doc := XML::XMLParser parse:'<foo><bla>123</bla><bla>abc</bla></foo>'. t := doc root tagName. "/ t now: 'foo' nodes := doc // 'bla'. "/ nodes now: a collection containing the bla DOM node firstBla := nodes first. firstBla characterData. "/ generates '123' secondBla := nodes at:2. secondBla characterData. "/ generates 'abc'
JSON[Bearbeiten]
Encoding to JSON[Bearbeiten]
Smalltalk:
|obj json| obj := Dictionary new. obj at:'foo' put:123. obj at:'baz' put:#(1 2 3). "/ an array obj['bar'] := 'someString'. "/ alternative syntax json := JSONPrinter toJSON:obj.
JavaScript:
var obj, json; obj = new Dictionary; obj['foo'] = 123; obj['baz'] = [1, 2, 3]; obj['bar'] = "someString"; json = JSONPrinter.toJSON(obj);
Decoding from JSON[Bearbeiten]
var json, obj; json = "{\"foo\":123,\"baz\":[1,2,3],\"bar\":\"someString\"}"; obj = JSONReader.fromJSON(json); Transcript.showCR(obj['foo']); Transcript.showCR(obj['bar']); Transcript.showCR(obj.baz()); // alternative: use getter