Does Dart have sprintf, or does it only have interpolation? - string

I would like to emulate C's sprintf("%02d", x); in Dart, but I can't find string formatting, only string interpolation.

String interpolation covers most of your needs. If you want to format numbers directly, there is also num.toStringAsPrecision().

I took a different approach to this issue: by padding the string directly, I don't have to use any libraries (mainly because the intl library seems to be discontinued):
x.toString().padLeft(2, "0");
Would be the equivalent of sprintf("%02d", x);

The intl library provides several helpers to format values.
See the API documentation at http://api.dartlang.org/docs/releases/latest/intl.html
Here is an example on how to convert a number into a two character string:
import 'package:intl/intl.dart';
main() {
var twoDigits = new NumberFormat("00", "en_US");
print(twoDigits.format(new Duration(seconds: 8)));
}

A String.format method does not currently exists but there is a bug/feature request for adding it.

Here is my implementation of String.format for Dart. It is not perfect but works good enough for me:
static String format(String fmt,List<Object> params) {
int matchIndex = 0;
String replace(Match m) {
if (matchIndex<params.length) {
switch (m[4]) {
case "f":
num val = params[matchIndex++];
String str;
if (m[3]!=null && m[3].startsWith(".")) {
str = val.toStringAsFixed(int.parse(m[3].substring(1)));
} else {
str = val.toString();
}
if (m[2]!=null && m[2].startsWith("0")) {
if (val<0) {
str = "-"+str.substring(1).padLeft(int.parse(m[2]),"0");
} else {
str = str.padLeft(int.parse(m[2]),"0");
}
}
return str;
case "d":
case "x":
case "X":
int val = params[matchIndex++];
String str = (m[4]=="d")?val.toString():val.toRadixString(16);
if (m[2]!=null && m[2].startsWith("0")) {
if (val<0) {
str = "-"+str.substring(1).padLeft(int.parse(m[2]),"0");
} else {
str = str.padLeft(int.parse(m[2]),"0");
}
}
return (m[4]=="X")?str.toUpperCase():str.toLowerCase();
case "s":
return params[matchIndex++].toString();
}
} else {
throw new Exception("Missing parameter for string format");
}
throw new Exception("Invalid format string: "+m[0].toString());
}
Test output follows:
format("%d", [1]) // 1
format("%02d", [2]) // 02
format("%.2f", [3.5]) // 3.50
format("%08.2f", [4]) // 00004.00
format("%s %s", ["A","B"]) // A B
format("%x", [63]) // 3f
format("%04x", [63]) // 003f
format("%X", [63]) //3F

Yes, Dart has a sprintf package:
https://pub.dev/packages/sprintf.
It is modeled after C's sprintf.

See a format package. It is similar to format() from Python. It is a new package. Needs testing.

Related

How can I convert a camel case string to snake case and back in idiomatic Kotlin?

Looking for code that will do conversions like this:
"MyCamelCaseA" to "my_camel_case_a"
"AMultiWordString" to "a_multi_word_string"
"my_camel_case_a" to "myCamelCaseA" or "MyCamelCaseA"
"a_multi_word_string" to "aMultiWordString" or "AMultiWordString"
Here are extensions to the String class that use regex and replacements to convert a string from camel case to snake case, and from snake case to camel case:
val camelRegex = "(?<=[a-zA-Z])[A-Z]".toRegex()
val snakeRegex = "_[a-zA-Z]".toRegex()
// String extensions
fun String.camelToSnakeCase(): String {
return camelRegex.replace(this) {
"_${it.value}"
}.toLowerCase()
}
fun String.snakeToLowerCamelCase(): String {
return snakeRegex.replace(this) {
it.value.replace("_","")
.toUpperCase()
}
}
fun String.snakeToUpperCamelCase(): String {
return this.snakeToLowerCamelCase().capitalize()
}
Here are examples using the String extension:
print("${"MyCamelCaseA".camelToSnakeCase()}\n")
my_camel_case_a
print("${"AMultiWordString".camelToSnakeCase()}\n")
a_multi_word_string
"my_camel_case_a".snakeToLowerCamelCase()
myCamelCaseA
"my_camel_case_a".snakeToUpperCamelCase()
MyCamelCaseA
Here's my stab at this.
fun String.camelToSnakeCase() = fold(StringBuilder(length)) { acc, c ->
if (c in 'A'..'Z') (if (acc.isNotEmpty()) acc.append('_') else acc).append(c + ('a' - 'A'))
else acc.append(c)
}.toString()
My approach is also written in the form of extension function, but it does not use regular expressions, instead going character-by-character, processing them and folding the processing result into the accumulator, which at the beginning is an empty StringBuilder. The processing is as follows:
if the character is not an upper-case Latin letter, add it to accumulator as is
if the character is an upper-case Latin letter, then also check if this is not the first character of the string (accumulator is not empty). If it is not, then add underscore to accumulator. Finally add lower-cased character.
One thing to note, is that kotlin.text.StringBuilder is used, not the JDK one.
I would go with these implementations:
fun String.toCamelCase() =
split('_').joinToString("", transform = String::capitalize)
... which splits the string using snakes as delimiters, and then reattaches the parts as capitalized words without a delimiter.
fun String.toSnakeCase() = replace(humps, "_").toLowerCase()
private val humps = "(?<=.)(?=\\p{Upper})".toRegex()
... which uses a regex to find the positions before humps, inserting snakes, and then converts the whole string to lowercase. The regex consists of two parts, the first one (?<=.) is a positive look-behind saying that it must be preceded by a character, and the second part (?=\\p{Upper}) is using a positive look-ahead saying it must be followed by an uppercase character.
If you have jackson-databind in your classpath, you can use the following utility function:
import com.fasterxml.jackson.databind.PropertyNamingStrategies
fun String.toSnakeCase(): String =
PropertyNamingStrategies.SnakeCaseStrategy().translate(this)
fun main() {
// should output this_is_the_case
println("thisIsTheCase".toSnakeCase())
}
this is my try with kotlin only
val camelCaseString = "thisIsCamelCase"
val snakeCaseString = camelCaseString.map {
if (it.isUpperCase()){
"_${it.toLowerCase()}"
}else
{"$it"}
}
.joinToString(separator = "")
System.out.println("here is your snake string: $snake_case_string")
here is your snake string: this_is_camel_case
convert from snake to camel
val snakeCaseString = "snake_case_string"
val camelCase = StringBuilder()
var prevChar = '$'
snakeCaseString.forEach {
if(prevChar.equals('_')){
camelCase.append(it.toUpperCase())
}else if(!it.equals('_')){
camelCase.append(it)
}
prevChar = it
}
System.out.println(camelCase.toString())
snakeCaseString
I took one of the answers here, added Title Case and changed the API a bit
val camelRegex = "(?<=[a-zA-Z])[A-Z]".toRegex()
val snakeRegex = "_[a-zA-Z]".toRegex()
#JvmInline
value class SnakeCaseString(private val string: String) {
fun toCamelCase(): String = snakeRegex.replace(string) { it.value.replace("_", "").uppercase() }
fun toUpperCamelCase(): String =
toCamelCase().replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
fun toTitleCase(): String = snakeRegex.replace(string) { it.value.replace("_", " ").uppercase() }
.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
}
#JvmInline
value class CamelCaseString(private val string: String) {
fun toSnakeCase(): String = camelRegex.replace(string) { "_${it.value}" }.lowercase()
fun toTitleCase(): String = camelRegex.replace(string) { "_${it.value}" }
.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
}
fun String.asSnakeCase() = SnakeCaseString(this)
fun String.asCamelCase() = CamelCaseString(this)
If you want a method with an input and output, this is how I did it:
private fun convertCamelToSnakeCase(camelCase : String) : String {
val snakeCase = StringBuilder()
for(character in camelCase) {
if(character.isUpperCase()) {
snakeCase.append("_${character.toLowerCase()}")
} else {
snakeCase.append(character)
}
}
return snakeCase.removePrefix("_").toString()
}

Swift - Replacing emojis in a string with whitespace

I have a method that detects urls in a string and returns me both the urls and the ranges where they can be found. Everything works perfectly until there are emojis on the string. For example:
"I'm gonna do this callenge as soon as I can swing again 😂😂😂\n http://youtu.be/SW_d3fGz1hk"
Because of the emojis, the url extracted from the text is http://youtu.be/SW_d3fGz1 instead of http://youtu.be/SW_d3fGz1hk. I figured that the easiest solution was to just replace the emojis on the string with whitespace characters (cause I need the range to be correct for some text styling stuff). Problem is, this is extremely hard to accomplish with Swift (most likely my abilities with the Swift String API is lacking).
I've been trying to do it like this but it seems that I cannot create a string from an array of unicode points:
var emojilessStringWithSubstitution: String {
let emojiRanges = [0x1F601...0x1F64F, 0x2702...0x27B0]
let emojiSet = Set(emojiRanges.flatten())
let codePoints: [UnicodeScalar] = self.unicodeScalars.map {
if emojiSet.contains(Int($0.value)) {
return UnicodeScalar(32)
}
return $0
}
return String(codePoints)
}
Am I approaching this problem the wrong way? Is replacing emojis the best solution here? If so, how can I do it?
Swift 5
Don't use this hardcoded way to detect emojis. In Swift 5 you can do it easily
let inputText = "Some 🖐string 😂😂😂 with 👹👹 👹 emoji 🖐"
let textWithoutEmoij = inputText.unicodeScalars
.filter { !$0.properties.isEmojiPresentation }
.reduce("") { $0 + String($1) }
print(textWithoutEmoij) // Some string with emoji
You can use pattern matching (for emoji patterns) to filter out emoji characters from your String.
extension String {
var emojilessStringWithSubstitution: String {
let emojiPatterns = [UnicodeScalar(0x1F601)...UnicodeScalar(0x1F64F),
UnicodeScalar(0x2702)...UnicodeScalar(0x27B0)]
return self.unicodeScalars
.filter { ucScalar in !(emojiPatterns.contains{ $0 ~= ucScalar }) }
.reduce("") { $0 + String($1) }
}
}
/* example usage */
let str = "I'm gonna do this callenge as soon as I can swing again 😂😂😂\n http://youtu.be/SW_d3fGz1hk"
print(str.emojilessStringWithSubstitution)
/* I'm gonna do this callenge as soon as I can swing again
http://youtu.be/SW_d3fGz1hk */
Note that the above only makes use of the emoji intervals as presented in your question, and is in no way representative for all emojis, but the method is general and can swiftly be extended by including additional emoji intervals to the emojiPatterns array.
I realize reading your question again that you'd prefer substituting emojis with whitespace characters, rather than removing them (which the above filtering solution does). We can achieve this by replacing the .filter operation above with a conditional return .map operation instead, much like in your question
extension String {
var emojilessStringWithSubstitution: String {
let emojiPatterns = [UnicodeScalar(0x1F600)...UnicodeScalar(0x1F64F),
UnicodeScalar(0x1F300)...UnicodeScalar(0x1F5FF),
UnicodeScalar(0x1F680)...UnicodeScalar(0x1F6FF),
UnicodeScalar(0x2600)...UnicodeScalar(0x26FF),
UnicodeScalar(0x2700)...UnicodeScalar(0x27BF),
UnicodeScalar(0xFE00)...UnicodeScalar(0xFE0F)]
return self.unicodeScalars
.map { ucScalar in
emojiPatterns.contains{ $0 ~= ucScalar } ? UnicodeScalar(32) : ucScalar }
.reduce("") { $0 + String($1) }
}
}
I the above, the existing emoji intervals has been extended, as per your comment to this post (listing these intervals), such that the emoji check is now possibly exhaustive.
Swift 4:
extension String {
func stringByRemovingEmoji() -> String {
return String(self.filter { !$0.isEmoji() })
}
}
extension Character {
fileprivate func isEmoji() -> Bool {
return Character(UnicodeScalar(UInt32(0x1d000))!) <= self && self <= Character(UnicodeScalar(UInt32(0x1f77f))!)
|| Character(UnicodeScalar(UInt32(0x2100))!) <= self && self <= Character(UnicodeScalar(UInt32(0x26ff))!)
}
}
Emojis are classified as symbols by Unicode. Character sets are typically used in searching operations. So we will use Character sets a property that is symbols.
var emojiString = "Hey there 🖐, welcome"
emojiString = emojiString.components(separatedBy: CharacterSet.symbols).joined()
print(emojiString)
Output is
Hey there , welcome
Now observe the emoji is replaced by a white space so there is two white space and we replace it by the following way
emojiString.replacingOccurrences(of: " ", with: " ")
The above method replace parameter of: "two white space" to with: "single white space"
Getting all emoji is more complicated than you would think. For more info on how to figure out which characters are emoji, check out this stackoverflow post or this article.
Building on that information, I would propose to use the extension on Character to more easily let us understand which characters are emoji. Then add a String extension to easily replace found emoji with another character.
extension Character {
var isSimpleEmoji: Bool {
guard let firstProperties = unicodeScalars.first?.properties else {
return false
}
return unicodeScalars.count == 1 &&
(firstProperties.isEmojiPresentation ||
firstProperties.generalCategory == .otherSymbol)
}
var isCombinedIntoEmoji: Bool {
return unicodeScalars.count > 1 &&
unicodeScalars.contains {
$0.properties.isJoinControl ||
$0.properties.isVariationSelector
}
}
var isEmoji: Bool {
return isSimpleEmoji || isCombinedIntoEmoji
}
}
extension String {
func replaceEmoji(with character: Character) -> String {
return String(map { $0.isEmoji ? character : $0 })
}
}
Using it would simply become:
"Some string 😂😂😂 with emoji".replaceEmoji(with: " ")
I found that the solutions given above did not work for certain characters such as 🏋️🏻‍♂️ and 🧰.
To find the emoji ranges, using regex I converted the full list of emoji characters to a file with just hex values. Then I converted them to decimal format and sorted them. Finally, I wrote a script to find the ranges.
Here is the final Swift extension for isEmoji().
extension Character {
func isEmoji() -> Bool {
let emojiRanges = [
(8205, 11093),
(12336, 12953),
(65039, 65039),
(126980, 129685)
]
let codePoint = self.unicodeScalars[self.unicodeScalars.startIndex].value
for emojiRange in emojiRanges {
if codePoint >= emojiRange.0 && codePoint <= emojiRange.1 {
return true
}
}
return false
}
}
For reference, here are the python scripts I wrote to parse the hex strings to integers and then find the ranges.
convert-hex-to-decimal.py
decimals = []
with open('hex.txt') as hexfile:
for line in hexfile:
num = int(line, 16)
if num < 256:
continue
decimals.append(num)
decimals = list(set(decimals))
decimals.sort()
with open('decimal.txt', 'w') as decimalfile:
for decimal in decimals:
decimalfile.write(str(decimal) + "\n")
make-ranges.py
first_line = True
range_start = 0
prev = 0
with open('decimal.txt') as hexfile:
for line in hexfile:
if first_line:
prev = int(line)
range_start = prev
first_line = False
continue
curr = int(line)
if prev + 1000 < curr: # 100 is abitrary to reduce number of ranges
print("(" + str(range_start) + ", " + str(prev) + ")")
range_start = curr
prev = curr
Don't hard-code the range of emojis, use this instead.
func 去除表情符号(字符串:String) -> String {
let 转换为Unicode = 字符串.unicodeScalars//https://developer.apple.com/documentation/swift/string
let 去除表情后的结果 = 转换为Unicode.filter { (item) -> Bool in
let 判断是否表情 = item.properties.isEmoji
return !判断是否表情//是表情就不保留
}
return String(去除表情后的结果)
}

Swap string case - swift

let str = "tHIS is A test"
let swapped_case = "This IS a TEST"
Swift noob here, how to do the second statement programatically?
This function works with all upper/lowercase characters
defined in Unicode, even those from "foreign" languages such as Ä or ć:
func swapCases(_ str : String) -> String {
var result = ""
for c in str.characters { // Swift 1: for c in str {
let s = String(c)
let lo = s.lowercased() //Swift 1 & 2: s.lowercaseString
let up = s.uppercased() //Swift 1 & 2: s.uppercaseString
result += (s == lo) ? up : lo
}
return result
}
Example:
let str = "tHIS is a test ÄöÜ ĂćŒ Α" // The last character is a capital Greek Alpha
let swapped_case = swapCases(str)
print(swapped_case)
// This IS A TEST äÖü ăĆœ α
Use switch statement in-range checks to determine letter case, and use NSString-bridged methods to convert accordingly.
let str = "tHIS is A test"
let swapped_case = "This IS a TEST"
func swapCase(string: String) -> String {
var swappedCaseString: String = ""
for character in string {
switch character {
case "a"..."z":
let uppercaseCharacter = (String(character) as NSString).uppercaseString
swappedCaseString += uppercaseCharacter
case "A"..."Z":
let lowercaseCharacter = (String(character) as NSString).lowercaseString
swappedCaseString += lowercaseCharacter
default:
swappedCaseString += String(character)
}
}
return swappedCaseString
}
swapCase(str)
I'm a bit too late but this works too :-)
let str = "tHIS is A test"
var res = ""
for c in str {
if contains("ABCDEFGHIJKLMNOPQRSTUVWXYZ", c) {
res += "\(c)".lowercaseString
} else {
res += "\(c)".uppercaseString
}
}
res
In Swift 5 I achieved it by creating a function which iterates through each character of the string, and using string methods to change each character I appended each character back into a new variable:
func reverseCase(string: String) -> String {
var newCase = ""
for char in string {
if char.isLowercase {
newCase.append(char.uppercased())
}
else if char.isUppercase {
newCase.append(char.lowercased())
}
else {
newCase.append(char)
}
}
return newCase
}
Then just pass your string through to the function when you call it in a print statement:
print(reverseCase(string: str))
You already have plenty of good succinct answers but here’s an over-elaborate one for fun.
Really this is a job for map – iterate over a collection (in this case String) and do a thing to each element (here, each Character). Except map takes any collection, but only gives you back an array, which you’d have to then turn into a String again.
But here’s a version of map that, given an extensible collection, gives you back that same kind of extensible collection.
(It does have the limitation of needing both collections to contain the same type, but that’s fine for strings. You could make it return a different type, but then you’d have to tell it which type you wanted i.e. map(s, transform) as String which would be annoying)
func map<C: ExtensibleCollectionType>(source: C, transform: (C.Generator.Element) -> C.Generator.Element) -> C {
var result = C()
for elem in source {
result.append(transform(elem))
}
return result
}
Then to write the transform function, first here’s an extension to character similar to the other answers. It does seem quite unsatisfying that you have to convert to a string just to uppercase a character, is there really no good (international characterset-friendly) way to do this?
extension Character {
var uppercaseCharacter: Character {
let s = String(self).uppercaseString
return s[s.startIndex]
}
var lowercaseCharacter: Character {
let s = String(self).lowercaseString
return s[s.startIndex]
}
}
And the function to flip the case. What I wonder is whether this pattern matching is international-friendly. It seems to be – "A"..."Z" ~= "Ä" returns true.
func flipCase(c: Character) -> Character {
switch c {
case "A"..."Z":
return c.lowercaseCharacter
case "a"..."z":
return c.uppercaseCharacter
default:
return c
}
}
Finally:
let s = map("Hello", flipCase)
// s is a String = "hELLO"
I hope this helps. inputString and resultString are the input and output respectively.
let inputString = "Example"
let outputString = inputString.characters.map { (character) -> Character in
let string = String(character)
let lower = string.lowercased()
let upper = string.uppercased()
return (string == lower) ? Character(upper) : Character(lower)
}
let resultString = String(outputString)

Comparing String.Index values

Is it possible to compare two String.Index values in Swift? I'm trying to process a string character by character, and several times I need to check if I am at the end of the string. I've tried just doing
while (currentIndex < string.endIndex) {
//do things...
currentIndex = currentIndex.successor()
}
Which complained about type conversions. Then, I tried defining and overload for < as such:
#infix func <(lhs: String.Index, rhs: String.Index) -> Bool {
var ret = true //what goes here?
return ret
}
Which gets rid of compilation errors, but I have no clue what to do in order to compare lhs and rhs properly. Is this the way I should go about using String.Index, or is there a better way to compare them?
The simplest option is the distance() function:
var string = "Hello World"
var currentIndex = string.startIndex
while (distance(currentIndex, string.endIndex) >= 0) {
println("currentIndex: \(currentIndex)")
currentIndex = currentIndex.successor()
}
Beware distance() has O(N) performance, so avoid it for large strings. However, the entire String class doesn't currently handle large strings anyway — you should probably switch to CFString if performance is critical.
Using an operator overload is a bad idea, but just as a learning exercise this is how you'd do it:
var string = "Hello World"
var currentIndex = string.startIndex
#infix func <(lhs: String.Index, rhs: String.Index) -> Bool {
return distance(lhs, rhs) > 0
}
while (currentIndex < string.endIndex) {
currentIndex = currentIndex.successor()
}
String indexes support = and !=. String indexes are an opaque type, not integers and can not be compared like integers.
Use: if (currentIndex != string.endIndex)
var currentIndex = string.startIndex
while (currentIndex != string.endIndex) {
println("currentIndex: \(currentIndex)")
currentIndex = currentIndex.successor()
}
I believe this REPL/Playground example should illuminate what you (and others) need to know about working with the String.Index concept.
// This will be our working example
let exampleString = "this is a string"
// And here we'll call successor a few times to get an index partway through the example
var someIndexInTheMiddle = exampleString.startIndex
for _ in 1...5 {
someIndexInTheMiddle = someIndexInTheMiddle.successor()
}
// And here we will iterate that string and detect when our current index is relative in one of three different possible ways to the character selected previously
println("\n\nsomeIndexInTheMiddle = \(exampleString[someIndexInTheMiddle])")
for var index: String.Index = exampleString.startIndex; index != exampleString.endIndex; index = index.successor() {
println(" - \(exampleString[index])")
if index != exampleString.startIndex && index.predecessor() == someIndexInTheMiddle {
println("current character comes after someIndexInTheMiddle")
} else if index == someIndexInTheMiddle {
println("current character is the one indicated by someIndexInTheMiddle")
} else if index != exampleString.endIndex && index.successor() == someIndexInTheMiddle {
println("Current character comes before someIndexinTheMiddle")
}
}
Hopefully that provides the necessary information.
Whatever way you decide to iterator over a String, you will immediately want to capture the iteration in a function that can be repeatedly invoked while using a closure applied to each string character. As in:
extension String {
func each (f: (Character) -> Void) {
for var index = self.startIndex;
index < self.endIndex;
index = index.successor() {
f (string[index])
}
}
}
Apple already provides these for C-Strings and will for general strings as soon as they get character access solidified.

How do I reverse a String in Dart?

I have a String, and I would like to reverse it. For example, I am writing an AngularDart filter that reverses a string. It's just for demonstration purposes, but it made me wonder how I would reverse a string.
Example:
Hello, world
should turn into:
dlrow ,olleH
I should also consider strings with Unicode characters. For example: 'Ame\u{301}lie'
What's an easy way to reverse a string, even if it has?
The question is not well defined. Reversing arbitrary strings does not make sense and will lead to broken output. The first (surmountable) obstacle is Utf-16. Dart strings are encoded as Utf-16 and reversing just the code-units leads to invalid strings:
var input = "Music \u{1d11e} for the win"; // Music 𝄞 for the win
print(input.split('').reversed.join()); // niw eht rof
The split function explicitly warns against this problem (with an example):
Splitting with an empty string pattern ('') splits at UTF-16 code unit boundaries and not at rune boundaries[.]
There is an easy fix for this: instead of reversing the individual code-units one can reverse the runes:
var input = "Music \u{1d11e} for the win"; // Music 𝄞 for the win
print(new String.fromCharCodes(input.runes.toList().reversed)); // niw eht rof 𝄞 cisuM
But that's not all. Runes, too, can have a specific order. This second obstacle is much harder to solve. A simple example:
var input = 'Ame\u{301}lie'; // Amélie
print(new String.fromCharCodes(input.runes.toList().reversed)); // eiĺemA
Note that the accent is on the wrong character.
There are probably other languages that are even more sensitive to the order of individual runes.
If the input has severe restrictions (for example being Ascii, or Iso Latin 1) then reversing strings is technically possible. However, I haven't yet seen a single use-case where this operation made sense.
Using this question as example for showing that strings have List-like operations is not a good idea, either. Except for few use-cases, strings have to be treated with respect to a specific language, and with highly complex methods that have language-specific knowledge.
In particular native English speakers have to pay attention: strings can rarely be handled as if they were lists of single characters. In almost every other language this will lead to buggy programs. (And don't get me started on toLowerCase and toUpperCase ...).
Here's one way to reverse an ASCII String in Dart:
input.split('').reversed.join('');
split the string on every character, creating an List
generate an iterator that reverses a list
join the list (creating a new string)
Note: this is not necessarily the fastest way to reverse a string. See other answers for alternatives.
Note: this does not properly handle all unicode strings.
I've made a small benchmark for a few different alternatives:
String reverse0(String s) {
return s.split('').reversed.join('');
}
String reverse1(String s) {
var sb = new StringBuffer();
for(var i = s.length - 1; i >= 0; --i) {
sb.write(s[i]);
}
return sb.toString();
}
String reverse2(String s) {
return new String.fromCharCodes(s.codeUnits.reversed);
}
String reverse3(String s) {
var sb = new StringBuffer();
for(var i = s.length - 1; i >= 0; --i) {
sb.writeCharCode(s.codeUnitAt(i));
}
return sb.toString();
}
String reverse4(String s) {
var sb = new StringBuffer();
var i = s.length - 1;
while (i >= 3) {
sb.writeCharCode(s.codeUnitAt(i-0));
sb.writeCharCode(s.codeUnitAt(i-1));
sb.writeCharCode(s.codeUnitAt(i-2));
sb.writeCharCode(s.codeUnitAt(i-3));
i -= 4;
}
while (i >= 0) {
sb.writeCharCode(s.codeUnitAt(i));
i -= 1;
}
return sb.toString();
}
String reverse5(String s) {
var length = s.length;
var charCodes = new List(length);
for(var index = 0; index < length; index++) {
charCodes[index] = s.codeUnitAt(length - index - 1);
}
return new String.fromCharCodes(charCodes);
}
main() {
var s = "Lorem Ipsum is simply dummy text of the printing and typesetting industry.";
time('reverse0', () => reverse0(s));
time('reverse1', () => reverse1(s));
time('reverse2', () => reverse2(s));
time('reverse3', () => reverse3(s));
time('reverse4', () => reverse4(s));
time('reverse5', () => reverse5(s));
}
Here is the result:
reverse0: => 331,394 ops/sec (3 us) stdev(0.01363)
reverse1: => 346,822 ops/sec (3 us) stdev(0.00885)
reverse2: => 490,821 ops/sec (2 us) stdev(0.0338)
reverse3: => 873,636 ops/sec (1 us) stdev(0.03972)
reverse4: => 893,953 ops/sec (1 us) stdev(0.04089)
reverse5: => 2,624,282 ops/sec (0 us) stdev(0.11828)
Try this function
String reverse(String s) {
var chars = s.splitChars();
var len = s.length - 1;
var i = 0;
while (i < len) {
var tmp = chars[i];
chars[i] = chars[len];
chars[len] = tmp;
i++;
len--;
}
return Strings.concatAll(chars);
}
void main() {
var s = "Hello , world";
print(s);
print(reverse(s));
}
(or)
String reverse(String s) {
StringBuffer sb=new StringBuffer();
for(int i=s.length-1;i>=0;i--) {
sb.add(s[i]);
}
return sb.toString();
}
main() {
print(reverse('Hello , world'));
}
The library More Dart contains a light-weight wrapper around strings that makes them behave like an immutable list of characters:
import 'package:more/iterable.dart';
void main() {
print(string('Hello World').reversed.join());
}
There is a utils package that covers this function. It has some more nice methods for operation on strings.
Install it with :
dependencies:
basic_utils: ^1.2.0
Usage :
String reversed = StringUtils.reverse("helloworld");
Github:
https://github.com/Ephenodrom/Dart-Basic-Utils
Here is a function you can use to reverse strings. It takes an string as input and will use a dart package called Characters to extract characters from the given string. Then we can reverse them and join again to make the reversed string.
String reverse(String string) {
if (string.length < 2) {
return string;
}
final characters = Characters(string);
return characters.toList().reversed.join();
}
Create this extension:
extension Ex on String {
String get reverse => split('').reversed.join();
}
Usage:
void main() {
String string = 'Hello World';
print(string.reverse); // dlroW olleH
}
Reversing "Hello World"

Resources