How to count a character occurrence in string in Nim, mainly using its native statements prior go to module ? eg.
var
str = "Hello World"
c : int
c = numChar( "o", str ) # <- illustration only ?
The earlier answer is correct but if you do not want to import any modules you can write your own procedure:
proc count_char(value: string = "Hello World", ch: char = 'o'): int =
var cnt_c: int = 0
for c in value:
if c == ch:
cnt_c += 1
result = cnt_c
var
val: string = "Mother Goose"
ch: char = 'o'
echo $count_char(val, ch)
PS: Unrelated - Need syntax highlight for nim-lang on SO.
Use the count function from strutils:
import std/strutils
let str = "Hello World"
let count = count(str, 'o')
assert count = 1
There’s also a string overload for counting sub strings as well.
This code fails to compile:
var s: ref string = nil
s = ref "hi"
echo s
The error is (2, 9) Error: type expected, but got: "hi". I've tried putting ref and ptr in front and back of the string, tried to find some example in the documentation, but failed.
var s: ref string
new(s)
s[] = "hi"
echo s[]
Declare
Allocate new object
Assign to dereferenced string
Echo final string in dereferenced form
Note that echo s[] is needed because ref string does not implement $ operator, and cannot be converted to string by echo.
Not entirely sure why you want to do this. But first you need to create your ref type, then assign the value to a string. Something like this:
var s: ref string = nil
echo s.repr
new s
s[] = "hi"
echo s[]
echo s.repr
Will output something like this:
nil
hi
ref 0x7f7d4bbcf050 --> 0x7f7d4bbd2090"hi"
But as I said, not sure why you'd want this. Strings are already a reference type. As long as you pass them as mutable to a procedure you will be able to modify the underlying data:
var s: string = ""
s = "hi"
echo s
echo s.repr
proc test(x: string) =
echo x.repr
proc testM(x: var string) =
echo x.repr
x[1] = 'o'
test s
testM s
echo s
echo s.repr
Will output something like:
hi
0x7f5fc2807060"hi"
0x7f5fc2807060"hi"
0x7f5fc2807060"hi"
ho
0x7f5fc2807060"ho"
I am running into a problem with Nim sequences and returning them from a function.
json_p.nim(42, 33) template/generic instantiation from here
json_p.nim(28, 22) Error: no generic parameters allowed for seq
Line 28 is where I define my key_list
proc get_json_keys(json_data: JsonNode) : seq =
var key_list: seq[string] = #[] # 28
var key: string
for record in json_data:
for key, value in record:
if (not key_list.contains(key)):
key_list.add(key)
return key_list
I just call it from a main.
proc main() : void =
var file = get_url()
var json_data = file.parseFile()
[...]
var key_list = get_json_keys(json_data)
for key in key_list:
echo key
The code works fine inside the main function.
Problems:
*seq is a generic dynamic array an you can only add the key and all search will be linear since it's like the C language array.
*All functions returning value have a default "result" named variable. You should use it to return your values.
*Using ".contains" will make nim search the entire array in order to check. The best option is use a container with fast search.
I'll assume you need:
*a function to handle json duplicate keys and return the unique list with fast key search.
Implementation:
import json,tables
proc get_json_keys(json : JsonNode):OrderedTable[string,string]=
#initialize the result object
result = initOrderedTable[string,string]()
#more info,see https://nim-lang.org/docs/json.html
for key,value in json.pairs():
#debugging...
#echo key & "-" & value.getStr()
if not result.contains(key):
result[key]=value.getStr()
var json_data = parseJson("""{"key1" :"value1","key2" :"value2" }""")
var key_list = get_json_keys(json_data)
for key in key_list.pairs() :
echo key
Output:
(Field0: "key1", Field1: "value1")
(Field0: "key2", Field1: "value2")
If search speed is not a issue, you can also do this way:
Implementation using seq:
proc get_json_keys(json : JsonNode):seq[string]=
result = newSeq[string](0)
for key,value in json.pairs():
if not result.contains(key):
result.add(key)
var json_data = parseJson("""{"key1" :"value1","key2" :"value2","key1":"value3" }""")
var key_list = get_json_keys(json_data)
echo key_list
Output:
#["key1", "key2"]
obs: edited my answer because seq is not immutable if declared with 'var'. It's only immutable if declared with 'let'.
Good old java way to conditionally append something to string is as follows:
if (booleanFlag) {
myString += "something to append"
}
Can I do the same in more groovy way, ideally in one line?
A very Groovy way to do this would be with GStrings:
"$myString${booleanFlag ? 'something to append' : ''}"
Here is a groovy way using GString closures:
>>> def world = false
>>> def people = true
>>>
>>> def message = "Hello${sw -> if (world) sw << ' World'; if (people) sw << ' People'}"
>>>
>>> message
Hello People
>>>
>>> people = false
>>> world = true
>>>
>>> message
Hello World
>>>
>>> world = false
>>> message
Hello
The string looks kinda long and could do with some indentation, but groovy shell did not allow me to split the lines. Switched to an IDE, turns out you can write the string better like this (with the help of triple quote strings):
def message =
"""Hello${sw ->
if (false) sw << ' World!'
if (false) sw << ' People!'
if (true) sw << ' Groovy!'
}"""
Now that's groovy!
Try:
def b = true
def s = 's'
s += b ? 's' : ''
Here's a solution creating a String.metaClass.when method:
String.metaClass.when = { it ? delegate : '' }
Testing:
flag = true
myString = 'foo '
myString += "to append".when flag
assert myString == 'foo to append'
myString = 'foo ' + "to append".when(false)
assert myString == 'foo '
I think this pattern is a good candidate for some meta-programming.
def myString = 'Hello'
use(StringBuilderCategory) {
assert new StringBuilder(myString).append(true, 'World').toString() == 'HelloWorld'
assert new StringBuilder(myString).append(false, 'World').toString() == 'Hello'
}
class StringBuilderCategory {
static StringBuilder append(StringBuilder builder, boolean condition, String str) {
if(condition) {
builder.append(str)
} else {
builder
}
}
}
I used a StringBuilder to avoid implying that Strings are mutable, but a similar method can be added to String to get it down to this:
use(TheCategory) {
myString = myString.append(booleanFlag, 'something to append')
}
Of course there's the option of using the meta class instead of a category.
Looks like one line to me:
if (booleanFlag) myString += "something to append";
How can I remove last character from String variable using Swift? Can't find it in documentation.
Here is full example:
var expression = "45+22"
expression = expression.substringToIndex(countElements(expression) - 1)
Swift 4.0 (also Swift 5.0)
var str = "Hello, World" // "Hello, World"
str.dropLast() // "Hello, Worl" (non-modifying)
str // "Hello, World"
String(str.dropLast()) // "Hello, Worl"
str.remove(at: str.index(before: str.endIndex)) // "d"
str // "Hello, Worl" (modifying)
Swift 3.0
The APIs have gotten a bit more swifty, and as a result the Foundation extension has changed a bit:
var name: String = "Dolphin"
var truncated = name.substring(to: name.index(before: name.endIndex))
print(name) // "Dolphin"
print(truncated) // "Dolphi"
Or the in-place version:
var name: String = "Dolphin"
name.remove(at: name.index(before: name.endIndex))
print(name) // "Dolphi"
Thanks Zmey, Rob Allen!
Swift 2.0+ Way
There are a few ways to accomplish this:
Via the Foundation extension, despite not being part of the Swift library:
var name: String = "Dolphin"
var truncated = name.substringToIndex(name.endIndex.predecessor())
print(name) // "Dolphin"
print(truncated) // "Dolphi"
Using the removeRange() method (which alters the name):
var name: String = "Dolphin"
name.removeAtIndex(name.endIndex.predecessor())
print(name) // "Dolphi"
Using the dropLast() function:
var name: String = "Dolphin"
var truncated = String(name.characters.dropLast())
print(name) // "Dolphin"
print(truncated) // "Dolphi"
Old String.Index (Xcode 6 Beta 4 +) Way
Since String types in Swift aim to provide excellent UTF-8 support, you can no longer access character indexes/ranges/substrings using Int types. Instead, you use String.Index:
let name: String = "Dolphin"
let stringLength = count(name) // Since swift1.2 `countElements` became `count`
let substringIndex = stringLength - 1
name.substringToIndex(advance(name.startIndex, substringIndex)) // "Dolphi"
Alternatively (for a more practical, but less educational example) you can use endIndex:
let name: String = "Dolphin"
name.substringToIndex(name.endIndex.predecessor()) // "Dolphi"
Note: I found this to be a great starting point for understanding String.Index
Old (pre-Beta 4) Way
You can simply use the substringToIndex() function, providing it one less than the length of the String:
let name: String = "Dolphin"
name.substringToIndex(countElements(name) - 1) // "Dolphi"
The global dropLast() function works on sequences and therefore on Strings:
var expression = "45+22"
expression = dropLast(expression) // "45+2"
// in Swift 2.0 (according to cromanelli's comment below)
expression = String(expression.characters.dropLast())
Swift 4:
let choppedString = String(theString.dropLast())
In Swift 2, do this:
let choppedString = String(theString.characters.dropLast())
I recommend this link to get an understanding of Swift strings.
Swift 4/5
var str = "bla"
str.removeLast() // returns "a"; str is now "bl"
This is a String Extension Form:
extension String {
func removeCharsFromEnd(count_:Int) -> String {
let stringLength = count(self)
let substringIndex = (stringLength < count_) ? 0 : stringLength - count_
return self.substringToIndex(advance(self.startIndex, substringIndex))
}
}
for versions of Swift earlier than 1.2:
...
let stringLength = countElements(self)
...
Usage:
var str_1 = "Maxim"
println("output: \(str_1.removeCharsFromEnd(1))") // "Maxi"
println("output: \(str_1.removeCharsFromEnd(3))") // "Ma"
println("output: \(str_1.removeCharsFromEnd(8))") // ""
Reference:
Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.)
See DOCS
Use the function removeAtIndex(i: String.Index) -> Character:
var s = "abc"
s.removeAtIndex(s.endIndex.predecessor()) // "ab"
Swift 4
var welcome = "Hello World!"
welcome = String(welcome[..<welcome.index(before:welcome.endIndex)])
or
welcome.remove(at: welcome.index(before: welcome.endIndex))
or
welcome = String(welcome.dropLast())
The easiest way to trim the last character of the string is:
title = title[title.startIndex ..< title.endIndex.advancedBy(-1)]
import UIKit
var str1 = "Hello, playground"
str1.removeLast()
print(str1)
var str2 = "Hello, playground"
str2.removeLast(3)
print(str2)
var str3 = "Hello, playground"
str3.removeFirst(2)
print(str3)
Output:-
Hello, playgroun
Hello, playgro
llo, playground
let str = "abc"
let substr = str.substringToIndex(str.endIndex.predecessor()) // "ab"
var str = "Hello, playground"
extension String {
var stringByDeletingLastCharacter: String {
return dropLast(self)
}
}
println(str.stringByDeletingLastCharacter) // "Hello, playgroun"
Short answer (valid as of 2015-04-16): removeAtIndex(myString.endIndex.predecessor())
Example:
var howToBeHappy = "Practice compassion, attention and gratitude. And smile!!"
howToBeHappy.removeAtIndex(howToBeHappy.endIndex.predecessor())
println(howToBeHappy)
// "Practice compassion, attention and gratitude. And smile!"
Meta:
The language continues its rapid evolution, making the half-life for many formerly-good S.O. answers dangerously brief. It's always best to learn the language and refer to real documentation.
With the new Substring type usage:
Swift 4:
var before: String = "Hello world!"
var lastCharIndex: Int = before.endIndex
var after:String = String(before[..<lastCharIndex])
print(after) // Hello world
Shorter way:
var before: String = "Hello world!"
after = String(before[..<before.endIndex])
print(after) // Hello world
Use the function advance(startIndex, endIndex):
var str = "45+22"
str = str.substringToIndex(advance(str.startIndex, countElements(str) - 1))
A swift category that's mutating:
extension String {
mutating func removeCharsFromEnd(removeCount:Int)
{
let stringLength = count(self)
let substringIndex = max(0, stringLength - removeCount)
self = self.substringToIndex(advance(self.startIndex, substringIndex))
}
}
Use:
var myString = "abcd"
myString.removeCharsFromEnd(2)
println(myString) // "ab"
Another way If you want to remove one or more than one character from the end.
var myStr = "Hello World!"
myStr = (myStr as NSString).substringToIndex((myStr as NSString).length-XX)
Where XX is the number of characters you want to remove.
Swift 3 (according to the docs) 20th Nov 2016
let range = expression.index(expression.endIndex, offsetBy: -numberOfCharactersToRemove)..<expression.endIndex
expression.removeSubrange(range)
The dropLast() function removes the last element of the string.
var expression = "45+22"
expression = expression.dropLast()
Swift 4.2
I also delete my last character from String (i.e. UILabel text) in IOS app
#IBOutlet weak var labelText: UILabel! // Do Connection with UILabel
#IBAction func whenXButtonPress(_ sender: UIButton) { // Do Connection With X Button
labelText.text = String((labelText.text?.dropLast())!) // Delete the last caracter and assign it
}
I'd recommend using NSString for strings that you want to manipulate. Actually come to think of it as a developer I've never run into a problem with NSString that Swift String would solve... I understand the subtleties. But I've yet to have an actual need for them.
var foo = someSwiftString as NSString
or
var foo = "Foo" as NSString
or
var foo: NSString = "blah"
And then the whole world of simple NSString string operations is open to you.
As answer to the question
// check bounds before you do this, e.g. foo.length > 0
// Note shortFoo is of type NSString
var shortFoo = foo.substringToIndex(foo.length-1)
Swift 3: When you want to remove trailing string:
func replaceSuffix(_ suffix: String, replacement: String) -> String {
if hasSuffix(suffix) {
let sufsize = suffix.count < count ? -suffix.count : 0
let toIndex = index(endIndex, offsetBy: sufsize)
return substring(to: toIndex) + replacement
}
else
{
return self
}
}
complimentary to the above code I wanted to remove the beginning of the string and could not find a reference anywhere. Here is how I did it:
var mac = peripheral.identifier.description
let range = mac.startIndex..<mac.endIndex.advancedBy(-50)
mac.removeRange(range) // trim 17 characters from the beginning
let txPower = peripheral.advertisements.txPower?.description
This trims 17 characters from the beginning of the string (he total string length is 67 we advance -50 from the end and there you have it.
I prefer the below implementation because I don't have to worry even if the string is empty
let str = "abc"
str.popLast()
// Prints ab
str = ""
str.popLast() // It returns the Character? which is an optional
// Print <emptystring>