How to replace n occurrence of a substring in a string in dart? - flutter

I want to replace n occurrence of a substring in a string.
myString = "I have a mobile. I have a cat.";
How I can replace the second have of myString

hope this simple function helps. You can also extract the function contents if you don't wish a function. It's just two lines with some
Dart magic
void main() {
String myString = 'I have a mobile. I have a cat.';
String searchFor='have';
int replaceOn = 2;
String replaceText = 'newhave';
String result = customReplace(myString,searchFor,replaceOn,replaceText);
print(result);
}
String customReplace(String text,String searchText, int replaceOn, String replaceText){
Match result = searchText.allMatches(text).elementAt(replaceOn - 1);
return text.replaceRange(result.start,result.end,replaceText);
}

Something like that should work:
String replaceNthOccurrence(String input, int n, String from, String to) {
var index = -1;
while (--n >= 0) {
index = input.indexOf(from, ++index);
if (index == -1) {
break;
}
}
if (index != -1) {
var result = input.replaceFirst(from, to, index);
return result;
}
return input;
}
void main() {
var myString = "I have a mobile. I have a cat.";
var replacedString = replaceNthOccurrence(myString, 2, "have", "had");
print(replacedString); // prints "I have a mobile. I had a cat."
}

This would be a better solution to undertake as it check the fallbacks also. Let me list down all the scenarios:
If position is 0 then it will replace all occurrence.
If position is correct then it will replace at same location.
If position is wrong then it will send back input string.
If substring does not exist in input then it will send back input string.
void main() {
String input = "I have a mobile. I have a cat.";
print(replacenth(input, 'have', 'need', 1));
}
/// Computes the nth string replace.
String replacenth(String input, String substr, String replstr,int position) {
if(input.contains(substr))
{
var splittedStr = input.split(substr);
if(splittedStr.length == 0)
return input;
String finalStr = "";
for(int i = 0; i < splittedStr.length; i++)
{
finalStr += splittedStr[i];
if(i == (position - 1))
finalStr += replstr;
else if(i < (splittedStr.length - 1))
finalStr += substr;
}
return finalStr;
}
return input;
}

let's try with this
void main() {
var myString = "I have a mobile. I have a cat.I have a cat";
print(replaceInNthOccurrence(myString, "have", "test", 1));
}
String replaceInNthOccurrence(
String stringToChange, String searchingWord, String replacingWord, int n) {
if(n==1){
return stringToChange.replaceFirst(searchingWord, replacingWord);
}
final String separator = "#######";
String splittingString =
stringToChange.replaceAll(searchingWord, separator + searchingWord);
var splitArray = splittingString.split(separator);
print(splitArray);
String result = "";
for (int i = 0; i < splitArray.length; i++) {
if (i % n == 0) {
splitArray[i] = splitArray[i].replaceAll(searchingWord, replacingWord);
}
result += splitArray[i];
}
return result;
}
here the regex
void main() {
var myString = "I have a mobile. I have a cat. I have a cat. I have a cat.";
final newString =
myString.replaceAllMapped(new RegExp(r'^(.*?(have.*?){3})have'), (match) {
return '${match.group(1)}';
});
print(newString.replaceAll(" "," had "));
}
Demo link

Here it is one more variant which allows to replace any occurrence in subject string.
void main() {
const subject = 'I have a dog. I have a cat. I have a bird.';
final result = replaceStringByOccurrence(subject, 'have', '*have no*', 0);
print(result);
}
/// Looks for `occurrence` of `search` in `subject` and replace it with `replace`.
///
/// The occurrence index is started from 0.
String replaceStringByOccurrence(
String subject, String search, String replace, int occurence) {
if (occurence.isNegative) {
throw ArgumentError.value(occurence, 'occurrence', 'Cannot be negative');
}
final regex = RegExp(r'have');
final matches = regex.allMatches(subject);
if (occurence >= matches.length) {
throw IndexError(occurence, matches, 'occurrence',
'Cannot be more than count of matches');
}
int index = -1;
return subject.replaceAllMapped(regex, (match) {
index += 1;
return index == occurence ? replace : match.group(0)!;
});
}
Tested on dartpad.

Related

Extract template tags {{..}} from a string in flutter

I need to extract squiggly bracketed template tags from a string. For example:
String str="Hello {{user}}, your reference is {{ref}}"
I would like a to extract the tags in-between the {{..}} into an List. For example:
["user","ref"]
How can I do this, for example with a Regx - I would need to ignore any whitespace in-side the brackets for example {{ user}} would need to return "user".
This question is exactly same as this que.. Want code for flutter dart.
You can use this regex
void main() {
RegExp re = RegExp(r'{{([^]*?)}}');
String data = "Hello {{user}}, your reference is {{ref}}";
var match = re.firstMatch(data);
if (match != null) print(match.group(1));
List something = re.allMatches(data).map((m)=>m[1]).toList();
print(something);
}
OUtput
user
[user, ref]
void main() {
String str="Hello {{user}}, your reference is {{ref}}";
List<String> lstr = getStringBetweenBracket(str);
print(lstr);
}
List<String> getStringBetweenBracket(String str) {
List<String> rstr = [];
var j = str.splitMapJoin(new RegExp(r'\{\{(.*?)\}\}'), onMatch: (e) {
if( e.group(0) != null)
return e.group(0)!.replaceAll("{{","").replaceAll("}}","")+",";
else
return "";
}, onNonMatch: (e) { return ""; });
if(j != "") {
rstr = j.split(",");
rstr.removeAt(rstr.length-1);
}
return rstr;
}
you can do this way get array of data
void main() {
String str="Hello {{user}}, your reference is {{ref}}";
var parts = str.split(' ');
print(parts);
print(parts[1]);
}
void main(){
String str = 'HelloTutorialKart.';
int startIndex = 5;
int endIndex = 13;
//find substring
String result = str.substring(startIndex, endIndex);
print(result);
}
output
Tutorial

How to convert double into string with 2 significant digits?

So i have small double values and i need to convert them into string in order to display in my app. But i care only about first two significant digits.
It should work like this:
convert(0.000000000003214324) = '0.0000000000032';
convert(0.000003415303) = '0.0000034';
We can convert double to string, then check every index and take up to two nonzero (also .) strings. But the issue comes on scientific notation for long double.
You can check Convert long double to string without scientific notation (Dart)
We need to find exact String value in this case. I'm taking help from this answer.
String convert(String number) {
String result = '';
int maxNonZeroDigit = 2;
for (int i = 0; maxNonZeroDigit > 0 && i < number.length; i++) {
result += (number[i]);
if (number[i] != '0' && number[i] != '.') {
maxNonZeroDigit -= 1;
}
}
return result;
}
String toExact(double value) {
var sign = "";
if (value < 0) {
value = -value;
sign = "-";
}
var string = value.toString();
var e = string.lastIndexOf('e');
if (e < 0) return "$sign$string";
assert(string.indexOf('.') == 1);
var offset =
int.parse(string.substring(e + (string.startsWith('-', e + 1) ? 1 : 2)));
var digits = string.substring(0, 1) + string.substring(2, e);
if (offset < 0) {
return "${sign}0.${"0" * ~offset}$digits";
}
if (offset > 0) {
if (offset >= digits.length) return sign + digits.padRight(offset + 1, "0");
return "$sign${digits.substring(0, offset + 1)}"
".${digits.substring(offset + 1)}";
}
return digits;
}
void main() {
final num1 = 0.000000000003214324;
final num2 = 0.000003415303;
final v1 = convert(toExact(num1));
final v2 = convert(toExact(num2));
print("num 1 $v1 num2 $v2");
}
Run on dartPad

Is there a way to replace multiple keywords in a string and wrapping them with their own keyword?

Say I have a string:
typed = "need replace this ap"
str = "hello I need to replace this asap"
so the end result I want would be this:
newStr = "hello I <bold>need</bold> to <bold>replace</bold> <bold>this</bold> as<bold>ap</bold>"
please don't mind the weird syntax.
I wonder if the order would matter, for example:
typed = "applicable app"
str = "the app is very applicable in many applications"
The end result I wish should be:
newStr = "the <bold>app</bold> is very <bold>applicable</bold> in many <bold>app</bold>lications"
right? is this possible?
Hey,If You can ignore the weird HTML syntax here,
Then I have wrote a solution for you,
Paste this code in dart pad here
removeDuplicates(var typed, var str) {
Map<String, String> m = new Map<String, String>();
var n = typed.length;
String ans = "";
//for storing the "typed" string (word by word) into a map "m" variable for later searching purpose
String temp = "";
int i = 0;
for (i = 0; i < n; i++) {
if (typed[i] == " ") {
m[temp] = temp;
temp = "";
} else {
temp = temp + typed[i];
}
}
//for storing the last word of the string "typed", coz loop will never find a space in last of the string
m[temp] = temp;
// map variable loop for search from map "m" in the "str" string, and matching if the word is present or not
var n2 = str.length;
String temp2 = "";
for (int j = 0; j < n2; j++) {
if (str[j] == " ") {
if (m.containsKey(temp2)) {
} else {
ans = ans + " " + temp2; //storing the "temp2" string into "ans" string, everytime it finds a space and if the string is not already present in the map "m"
}
temp2 = "";
} else {
temp2 = temp2 + str[j];
}
}
//for searching for the last word of the string "str" in map "m", coz loop will never find a space in last of the string,
if (m.containsKey(temp2)) {
} else {
ans = ans + " " + temp2;
}
return ans;
}
void main() {
String typed = "need replace this ap";
var str = "hello I need to replace this asap";
String answer = removeDuplicates(typed, str);
print(answer);
}
Here, I have made a method removeDuplicates() to simplify your work, You just have to pass those string in your method, and then it will return you the desired answer string by removing the duplicates, with a new string.
UPDATED CODE (TO SHOW HTML CODE):
removeDuplicates(var typed, var str) {
Map<String, String> m = new Map<String, String>();
var n = typed.length;
String ans = "";
//for storing the "typed" string (word by word) into a map "m" variable for later searching purpose
String temp = "";
int i = 0;
for (i = 0; i < n; i++) {
if (typed[i] == " ") {
m[temp] = temp;
temp = "";
} else {
temp = temp + typed[i];
}
}
//for storing the last word of the string "typed", coz loop will never find a space in last of the string
m[temp] = temp;
print(m);
// map variable loop for search from map "m" in the "str" string, and matching if the word is present or not
var n2 = str.length;
String temp2 = "";
for (int j = 0; j < n2; j++) {
if (str[j] == " ") {
if (m.containsKey(temp2)) {
temp2 = "<bold>" + temp2 + "</bold> ";
ans = ans + " " + temp2;
} else {
ans = ans +
" " +
temp2; //storing the "temp2" string into "ans" string, everytime it finds a space and if the string is not already present in the map "m"
}
temp2 = "";
} else {
temp2 = temp2 + str[j];
}
}
//for searching for the last word of the string "str" in map "m", coz loop will never find a space in last of the string,
if (m.containsKey(temp2)) {
temp2 = "<bold>" + temp2 + "</bold> ";
temp2 = "";
} else {
ans = ans + " " + temp2;
temp2 = "";
}
return ans;
}
void main() {
var typed = "applicable app";
var str = "the app is very applicable in many applications";
String answer = removeDuplicates(typed, str);
print(answer);
}
UPDATE 2 (ALL THANKS TO PSKINK FOR THE str.replaceAllMapped APPROACH)
replaceWithBoldIfExists(String typed, String str) {
var n = typed.length;
List<String> searchList = new List<String>();
String temp = "";
int i = 0;
for (i = 0; i < n; i++) {
if (typed[i] == " ") {
searchList.add(temp);
temp = "";
} else {
temp = temp + typed[i];
}
}
searchList.add(temp);
String pat = searchList.join('|');
final pattern = RegExp(pat);
final replaced =
str.replaceAllMapped(pattern, (m) => '<bold>${m.group(0)}</bold>');
return replaced;
}
void main() {
var typed = "need replace this ap";
var str = "hello I need to replace this asap";
print(replaceWithBoldIfExists(typed, str));
}

Filter out a range of characters in dart

I have a string like <p>[var # example] <h1>Title</h1>[visual compose]</p>I want to filter out all the substrings which are inside square brackets, including the square brackets.
Do you mean you want to remove them?
You can do it with RegExp, but I would use a parser when html is involved.
One solution is this:
https://dartpad.dartlang.org/a92f2181191e23ee587d57fb55246c1f
String filterShortcodes(String input,
{String opening = '[', String closing = ']'}) {
assert(opening.runes.length == 1);
assert(closing.runes.length == 1);
final openingRune = opening.runes.first;
final closingRune = closing.runes.first;
bool filter = false;
final buf = StringBuffer();
for (final rune in input.runes) {
if (filter == false && rune == openingRune) {
filter = true;
} else if (filter == true && rune == closingRune) {
filter = false;
} else if (!filter) {
buf.write(String.fromCharCode(rune));
}
}
return buf.toString();
}
void main() {
var input = '<p>[var # example] <h1>Title</h1>[visual compose]</p>';
print(filterShortcodes(input)); // <p> <h1>Title</h1></p>
}
String removeTextBetweenSquareBrackets(String input) {
return input.replaceAll(new RegExp(r'\[.*?\]'), "");
}
void main() {
print(removeTextBetweenSquareBrackets('<p>[var # example] <h1>Title</h1>[visual compose]</p>'));
}

Format string to phone number with (123) 456-6789 pattern using dart

Here is my code
void main() {
String phoneNumber = '123456789';
String formattedPhoneNumber = phoneNumber.replaceFirst("(\d{3})(\d{3})(\d+)", "(\$1) \$2-\$3");
print('Formatted number ${formattedPhoneNumber}');
}
Output:
Formatted number 123456789
I want output as Formatted number (123) 456-6789
Try this
print('1234567890'.replaceAllMapped(RegExp(r'(\d{3})(\d{3})(\d+)'), (Match m) => "(${m[1]}) ${m[2]}-${m[3]}"));
Create a custom Masked class
import 'package:flutter/material.dart';
class MaskedTextController extends TextEditingController {
MaskedTextController({String text, this.mask, Map<String, RegExp> translator})
: super(text: text) {
this.translator = translator ?? MaskedTextController.getDefaultTranslator();
this.addListener(() {
var previous = this._lastUpdatedText;
if (this.beforeChange(previous, this.text)) {
this.updateText(this.text);
this.afterChange(previous, this.text);
} else {
this.updateText(this._lastUpdatedText);
}
});
this.updateText(this.text);
}
String mask;
Map<String, RegExp> translator;
Function afterChange = (String previous, String next) {};
Function beforeChange = (String previous, String next) {
return true;
};
String _lastUpdatedText = '';
void updateText(String text) {
if(text != null){
this.text = this._applyMask(this.mask, text);
}
else {
this.text = '';
}
this._lastUpdatedText = this.text;
}
void updateMask(String mask, {bool moveCursorToEnd = true}) {
this.mask = mask;
this.updateText(this.text);
if (moveCursorToEnd) {
this.moveCursorToEnd();
}
}
void moveCursorToEnd() {
var text = this._lastUpdatedText;
this.selection = new TextSelection.fromPosition(
new TextPosition(offset: (text ?? '').length));
}
#override
void set text(String newText) {
if (super.text != newText) {
super.text = newText;
this.moveCursorToEnd();
}
}
static Map<String, RegExp> getDefaultTranslator() {
return {
'A': new RegExp(r'[A-Za-z]'),
'0': new RegExp(r'[0-9]'),
'#': new RegExp(r'[A-Za-z0-9]'),
'*': new RegExp(r'.*')
};
}
String _applyMask(String mask, String value) {
String result = '';
var maskCharIndex = 0;
var valueCharIndex = 0;
while (true) {
// if mask is ended, break.
if (maskCharIndex == mask.length) {
break;
}
// if value is ended, break.
if (valueCharIndex == value.length) {
break;
}
var maskChar = mask[maskCharIndex];
var valueChar = value[valueCharIndex];
// value equals mask, just set
if (maskChar == valueChar) {
result += maskChar;
valueCharIndex += 1;
maskCharIndex += 1;
continue;
}
// apply translator if match
if (this.translator.containsKey(maskChar)) {
if (this.translator[maskChar].hasMatch(valueChar)) {
result += valueChar;
maskCharIndex += 1;
}
valueCharIndex += 1;
continue;
}
// not masked value, fixed char on mask
result += maskChar;
maskCharIndex += 1;
continue;
}
return result;
}
}
Now call it in your main dart file
var maskedController = MaskedTextController(mask: '(000) 000-0000');
TextField(
controller: maskedController,
style: Styles.textNormalStyle,
maxLines: 1,
),
This solution work for your this specific Question and scenario.
you can achieve using following code.
String formattedPhoneNumber = "(" + phoneNumber.substring(0,3) + ") " +
phoneNumber.substring(3,6) + "-" +phoneNumber.substring(6,phoneNumber.length);
Ricardo pointed to a great library but his answer is half right. Besides the intl_phone_number_input you need to get libphonenumber_plugin installed as well.
intl_phone_number_input: ^0.7.0+2
libphonenumber_plugin:
The method getRegionInfoFromPhoneNumber "discovers" what country the number is from eg +55... it would interpret as it's from Brasil and proceed to format the phone number accordingly. You can also explicitly tell from where the phone number is from passing the country's acronym into the method eg. await PhoneNumber.getRegionInfoFromPhoneNumber(phone, "US"); It'll disregard a country code if it doesn't fit the number you're entering.
String phone = "+19795555555";
PhoneNumber number =
await PhoneNumber.getRegionInfoFromPhoneNumber(phone);
String formattedNumber = await PhoneNumberUtil.formatAsYouType(
number.phoneNumber!,
number.isoCode!,
);
print(formattedNumber); // -> prints: '+1 979-555-5555'
Also you can use: https://pub.dev/packages/intl_phone_number_input/example
String phoneNumber = '+234 500 500 5005';
PhoneNumber number = await PhoneNumber.getRegionInfoFromPhoneNumber(phoneNumber);
String parsableNumber = number.parseNumber();
`controller reference`.text = parsableNumber