I get Ids in a String format that contain leading zeroes. I would like to keep this String format but without the leading zeroes. Example:
00 => 0
01 => 1
02 => 2
10 => 10
11 => 11
My current implementation is
String id = int.parse(originalId).toString()
Is there a better / efficient / Dart pattern way to achieve this conversion ?
You could use RegExp which may be uglier but faster than double conversion :
"01".replaceAll(new RegExp(r'^0+(?=.)'), '')
´^´ matches the begining of the string
0+ matches one or more 0 character
(=?.) matches a group (()) of any characters except line breaks (.) without including it in the result (=?), this ensures that not the entire string will be matched so that we keep at least one zero if there are only zeroes.
Example :
void main() {
final List nums = ["00", "01", "02", "10", "11"];
final RegExp regexp = new RegExp(r'^0+(?=.)');
for (String s in nums) {
print("$s => ${s.replaceAll(regexp, '')}");
}
}
Result :
00 => 0
01 => 1
02 => 2
10 => 10
11 => 11
EDIT : Performance test thanks to your comment
void main() {
Stopwatch stopwatch = Stopwatch()..start();
final RegExp reg = RegExp(r'^0+(?=.)');
for (int i = 0; i < 20000000; i++) {
'05'.replaceAll(reg, '');
}
print('RegExp executed in ${stopwatch.elapsed}');
stopwatch = Stopwatch()..start();
for (int i = 0; i < 20000000; i++) {
int.parse('05').toString();
}
print('Double conversion executed in ${stopwatch.elapsed}');
}
Result :
RegExp executed in 0:00:02.912000
Double conversion executed in 0:00:03.216000
The more operations you will do the more it will be efficient compared to double conversion. However RegExp may be slower in a single computation because creating it has a cost, but we speak about a few microseconds... I would say that unless you have tens of thousands of operations just use the more convenient to you.
If anyone is trying to prevent leading zeros in a TextField, I made a TextInputFormatter that will remove all leading zeros once a non-zero number is added.
class NoLeadingZeros extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue,
TextEditingValue newValue,
) {
if (newValue.text.startsWith('0') && newValue.text.length > 1) {
return TextEditingValue().copyWith(
text: newValue.text.replaceAll(new RegExp(r'^0+(?=.)'), ''),
selection: newValue.selection.copyWith(
baseOffset: newValue.text.length - 1,
extentOffset: newValue.text.length - 1,
),
);
} else {
return newValue;
}
}
}
The tricky part is adjusting the TextSelection offsets once the zeros are removed. Without this update, the TextField will stop working.
I think you have the most elegant form already! There options for toStringAsFixed (https://api.dart.dev/stable/1.19.1/dart-core/num/toStringAsFixed.html, mostly floating points) and NumberFormat (https://pub.dev/documentation/intl/latest/intl/NumberFormat-class.html), but I feel these might not cover your case
If you have string value such as "01","001","0230" and If you want to remove leading zero then try this method. Worked for me.
num.parse('001').toInt() // where 001 is a string with leading zero
Thanks, Keep Learning
Related
This question already has answers here:
Calculate string value in javascript, not using eval
(12 answers)
Closed 4 months ago.
When the text was '2+3+5+1', the logic was easy
Split('+') so the string is converted to an array.
loop over the array and calculate the sum.
check the code below
void main() {
const text = '2+3+5+1';
final array = text.split('+');
int res =0;
for (var i=0; i<= array.length -1; i++){
res+=int.parse(array[i]);;
}
print(array);
print(res);
}
Now this String "2+3-5+1" contains minus.
how to get the right response using split method?
I am using dart.
note: I don't want to use any library (math expression) to solve this exercice.
Use the .replace() method.
text = text.replace("-", "+-");
When you run through the loop, it will calculate (-).
You can split your string using regex text.split(/\+|\-/).
This of course will fail if any space is added to the string (not to mention *, / or even decimal values).
const text = '20+3-5+10';
const arr = text.split(/\+|\-/)
let tot = 0
for (const num of arr) {
const pos = text.indexOf(num)
if (pos === 0) {
tot = parseInt(num)
} else {
switch (text.substr(text.indexOf(num) - 1, 1)) {
case '+':
tot += parseInt(num)
break
case '-':
tot -= parseInt(num)
break
}
}
}
console.log(tot)
I see 2 maybe 3 options, definitely there are hundreds
You don't use split and you just iterate through the string and just add or subtract on the way. As an example
You have '2+3-5+1'. You iterate until the second operator (+ or -) on your case. When you find it you just do the operation that you have iterated through and then you just keep going. You can do it recursive or not, doesn't matter
"2+3-5+1" -> "5-5+1" -> "0+1" -> 1
You use split on + for instance and you get [ '2', '3-5', '1' ] then you go through them with a loop with 2 conditions like
if(isNaN(x)) res+= x since you know it's been divided with a +
if(!isNaN(x)) res+= x.split('-')[0] - x.split('-')[1]
isNaN -> is not a number
Ofc you can make it look nicer. If you have parenthesis though, none of this will work
You can also use regex like split(/[-+]/) or more complex, but you'll have to find a way to know what operation follows each digit. One easy approach would be to iterate through both arrays. One of numbers and one of operators
"2+3-5+1".split(/[-+]/) -> [ '2', '3', '5', '1' ]
"2+3-5+1".split(/[0-9]*/).filter(x => x) -> [ '+', '-', '+' ]
You could probably find better regex, but you get the idea
You can ofc use a map or a switch for multiple operators
How to iterate digits of integer? for example sum of digits here, it works, but is any way to right way?
int sumOfDigits(int num) {
int sum = 0;
String numtostr = num.toString();
for (var i = 0; i < numtostr.length; i++) {
sum = sum + int.parse(numtostr[i]);
}
return sum;
}
If you're looking for a shorter way to do this, you can combine split, map and reduce
int sum = num.split('').map((e) => int.parse(e)).reduce((t, e) => t + e);
You can even do this:
int sum = num.split('').map(int.parse).reduce((t, e) => t + e);
Thank you #julemand101
It's fairly inefficient to create a string, then split the string, and parse the individual digits back to integers.
How about something like:
Iterable<int> digitsOf(int number) sync* {
do {
yield = number.remainder(10);
number ~/= 10;
} while (number != 0);
}
This iterates the digits of the (non-negative) number in base 10, from least significant to most significant, without allocating any strings along the way.
If you want the digits in the reverse order, you can either create a list from the iterable above and reverse it, or use a different approach:
Iterable<int> digitsHighToLow(int number) sync* {
var base = 1;
while (base * 10 < number) {
base = base * 10;
}
do {
var digit = number ~/ base;
yield digit;
number = (number - digit * base) * 10;
} while (number != 0);
}
(again, only works on non-negative numbers, you'll have to figure out what you want for negative numbers, either throw, or try negating the number, it's the same digits after all, or something else).
I am trying to find the largest 5 digit number in a series, made up of consecutive digits.
Code:
import 'dart:math';
int solution(String digits) {
List<int> sequence = digits.split('').map((digit) => int.parse(digit)).toList();
List<int> fiveDigitNumbers = List<int>();
sequence.fold(sequence, (remainder, digit) {
fiveDigitNumbers.add(int.parse(remainder.take(5).join()));
remainder = remainder.skip(5).toList();
return remainder;
});
return fiveDigitNumbers.isEmpty ? 0: fiveDigitNumbers.reduce((largest, number) => max(largest, number));
}
void main() {
print(solution('12345').toString());
}
Error:
FormatException: Invalid number (at character 1)
^
Stack Trace:
dart:core int.parse
package:solution/solution.dart 8:30 solution.
dart:collection _ListBase&Object&ListMixin.fold
package:solution/solution.dart 7:12 solution
test/solution_test.dart 6:12 main.
The stack trace shows the exception is thrown at line 8 and column 30, which is the int.parse() call. int.parse() will throw that exception for an empty string. Joining an empty List will produce an empty string. The remainder list will get empty before fold has iterated over every digit. Rather use another looping construct, e.g. while.
int solution(String digits) {
List<int> sequence = digits.split('').map((digit) => int.parse(digit)).toList();
var fiveDigitNumbers = List<int>();
while (! sequence.isEmpty) {
fiveDigitNumbers.add(int.parse(sequence.take(5).join()));
sequence = sequence.skip(1).toList();
}
return fiveDigitNumbers.isEmpty
? 0
: fiveDigitNumbers.reduce((largest, number) => max(largest, number));
}
i'm developing an app related to social messanging and i want to convert big numbers to Human readable format (e.g. 1500 to 1.5k) and also i'm new to Dart.
Your help will be appreciated.
You can use the NumberFormat class of flutter which has some in built functions for results you want..
Check out this link for NumberFormat class of flutter
Example:
This is one way if you want to use currency..
var _formattedNumber = NumberFormat.compactCurrency(
decimalDigits: 2,
symbol: '', // if you want to add currency symbol then pass that in this else leave it empty.
).format(numberToFormat);
print('Formatted Number is: $_formattedNumber');
Example:
This example is with locale.
var _formattedNumber = NumberFormat.compactCurrency(
decimalDigits: 2,
locale: 'en_IN'
symbol: '',
).format(numberToFormat);
print('Formatted Number is: $_formattedNumber');
The output of this is code would be:
If 1000 is entered then 1K is the output
Another way is by just using NumberFormat.compact() which gives the desired output...
// In this you won't have to worry about the symbol of the currency.
var _formattedNumber = NumberFormat.compact().format(numberToFormat);
print('Formatted Number is: $_formattedNumber');
The output of above example will also be:
If 1000 is entered then 1K is the output
I tried this and is working...
Make a class and used its static method every where.
class NumberFormatter{
static String formatter(String currentBalance) {
try{
// suffix = {' ', 'k', 'M', 'B', 'T', 'P', 'E'};
double value = double.parse(currentBalance);
if(value < 1000000){ // less than a million
return value.toStringAsFixed(2);
}else if(value >= 1000000 && value < (1000000*10*100)){ // less than 100 million
double result = value/1000000;
return result.toStringAsFixed(2)+"M";
}else if(value >= (1000000*10*100) && value < (1000000*10*100*100)){ // less than 100 billion
double result = value/(1000000*10*100);
return result.toStringAsFixed(2)+"B";
}else if(value >= (1000000*10*100*100) && value < (1000000*10*100*100*100)){ // less than 100 trillion
double result = value/(1000000*10*100*100);
return result.toStringAsFixed(2)+"T";
}
}catch(e){
print(e);
}
}
}
This function returns a ctypes.unsigned_char.array() and I do read string on it. It is getting the titles of windows. The problem is sometimes it throws TypeError.
try {
console.error('straight readString on XWindowGetProperty data:', rez_GP.data.readString());
} catch (ex) {
console.error('ex on straight readString:', ex);
}
Please notice the rez_GP.data.readString()
For example this instance: TypeError: malformed UTF-8 character sequence at offset 48. In this situation the window title is Editing js-macosx/bootstrap.js at base-template · Noitidart/js-macosx - Mozilla Firefox The 48th offset is that dot chracter you see, it's chracter code is 183. How to do readString() on this buffer without getting this error?
Thanks
readString expects a utf-8 encoded string. This is true for strings returned by _NET_WM_NAME, but not for WM_NAME.
I found a way to read the string propertly even ifs not utf-8, but im not sure if its he best way or the recommended way. This works though, i have to cast it to unsigned_char (must be this, so not char or jschar) then do fromCharCode:
function readAsChar8ThenAsChar16(stringPtr, known_len, jschar) {
// when reading as jschar it assumes max length of 500
// stringPtr is either char or jschar, if you know its jschar for sure, pass 2nd arg as true
// if known_len is passed, then assumption is not made, at the known_len position in array we will see a null char
// i tried getting known_len from stringPtr but its not possible, it has be known, i tried this:
//"stringPtr.contents.toString()" "95"
//"stringPtr.toString()" "ctypes.unsigned_char.ptr(ctypes.UInt64("0x7f73d5c87650"))"
// so as we see neither of these is 77, this is for the example of "_scratchpad/EnTeHandle.js at master · Noitidart/_scratchpad - Mozilla Firefox"
// tries to do read string on stringPtr, if it fails then it falls to read as jschar
var readJSCharString = function() {
var assumption_max_len = known_len ? known_len : 500;
var ptrAsArr = ctypes.cast(stringPtr, ctypes.unsigned_char.array(assumption_max_len).ptr).contents; // MUST cast to unsigned char (not ctypes.jschar, or ctypes.char) as otherwise i dont get foreign characters, as they are got as negative values, and i should read till i find a 0 which is null terminator which will have unsigned_char code of 0 // can test this by reading a string like this: "_scratchpad/EnTeHandle.js at master · Noitidart/_scratchpad - Mozilla Firefox" at js array position 36 (so 37 if count from 1), we see 183, and at 77 we see char code of 0 IF casted to unsigned_char, if casted to char we see -73 at pos 36 but pos 77 still 0, if casted to jschar we see chineese characters in all spots expect spaces even null terminator is a chineese character
console.info('ptrAsArr.length:', ptrAsArr.length);
//console.log('debug-msg :: dataCasted:', dataCasted, uneval(dataCasted), dataCasted.toString());
var charCode = [];
var fromCharCode = []
for (var i=0; i<ptrAsArr.length; i++) { //if known_len is correct, then will not hit null terminator so like in example of "_scratchpad/EnTeHandle.js at master · Noitidart/_scratchpad - Mozilla Firefox" if you pass length of 77, then null term will not get hit by this loop as null term is at pos 77 and we go till `< known_len`
var thisUnsignedCharCode = ptrAsArr.addressOfElement(i).contents;
if (thisUnsignedCharCode == 0) {
// reached null terminator, break
console.log('reached null terminator, at pos: ', i);
break;
}
charCode.push(thisUnsignedCharCode);
fromCharCode.push(String.fromCharCode(thisUnsignedCharCode));
}
console.info('charCode:', charCode);
console.info('fromCharCode:', fromCharCode);
var char16_val = fromCharCode.join('');
console.info('char16_val:', char16_val);
return char16_val;
}
if (!jschar) {
try {
var char8_val = stringPtr.readString();
console.info('stringPtr.readString():', char8_val);
return char8_val;
} catch (ex if ex.message.indexOf('malformed UTF-8 character sequence at offset ') == 0) {
console.warn('ex of offset utf8 read error when trying to do readString so using alternative method, ex:', ex);
return readJSCharString();
}
} else {
return readJSCharString();
}
}