Getting substring of a string in flutter that contain and emoji can cause a render failure - flutter

As part of the app I am shortening a user-given string to 40 characters and appending ellipses at the end if the string is longer than 40 characters. The users are allowed/able to use emoji in their strings.
If a string that is cut off has an emoji at the 40-character mark it causes it to fail to render and renders as a "�".
Is there a way to reliably get a sub-string of a text but without running into this issue?
Current code:
if (useStr.length > 40) {
useStr = useStr.substring(0, 40) + "...";
}

You should use package:characters and truncate strings based on graphemes (human-perceived characters) and not on (UTF-16) code units.
import 'package:characters/characters.dart';
void main() {
final originalString = '\u{1F336}\uFE0F' * 3; // 🌶️🌶️🌶️
const ellipsis = '\u2026';
for (var i = 1; i < 4; i += 1) {
var s = originalString;
var characters = s.chararacters;
if (characters.length > i) {
s = '${characters.take(i)}$ellipsis';
}
print(s);
}
}
which prints:
🌶️…
🌶️🌶️…
🌶️🌶️🌶️

Related

Unable to get substring in flutter and wrong string length

I am working on application to show mobile contact list with initials in a circle, but not getting initial character for some contact names.
In below code, first name is from mobile's contact list and second one I have typed from keyboard.
I am able to get correct length and also first character of the second name, but length for first name is double and also not able to get first character (it gives �).
print("𝙽𝚊𝚐𝚎𝚜𝚑".substring(0,1)); //�
print("𝙽𝚊𝚐𝚎𝚜𝚑".length); //12
print("Nagesh".substring(0,1)); //N
print("Nagesh".length); //6
Thankyou in advance for answering....
You can use this function to use substring with unicode:
subOnCharecter({required String str, required int from, required int to}) {
var runes = str.runes.toList();
String result = '';
for (var i = from; i < to; i++) {
result = result + String.fromCharCode(runes[i]);
}
return result;
}
and you can use it like this:
print(subOnCharecter(str: "𝙽𝚊𝚐𝚎𝚜𝚑", from: 0, to: 2)); // 𝙽𝚊
print(subOnCharecter(str: "Nagesh", from: 0, to: 2)); // Na
you can use this function instead of default substring.
The strings look similar, but they consist of different unicode characters.
Character U+1d67d "𝙽" is not the same as U+004e "N".
You can use str.runes.length to get the number of unicode characters.
A detailed explanation why the string length is different can be found here
example:
void main() {
var mobileStr = "𝙽𝚊𝚐𝚎𝚜𝚑";
var keyboardStr = "Nagesh";
analyzeString(mobileStr);
print("");
analyzeString(keyboardStr);
}
void analyzeString(String s) {
Runes runes = s.runes; // Unicode code-points of this string
var unicodeChars = runes.map((r) => r.toRadixString(16)).toList();
print("String: $s");
print("String length: ${s.length}");
print("Number of runes: ${runes.length}");
print("unicode characters: ${unicodeChars.join(" ")}");
}
// OUTPUT
// String: 𝙽𝚊𝚐𝚎𝚜𝚑
// String length: 12
// Number of runes: 6
// unicode characters: 1d67d 1d68a 1d690 1d68e 1d69c 1d691
// String: Nagesh
// String length: 6
// Number of runes: 6
// unicode characters: 4e 61 67 65 73 68

flutter how to compare two different format phone numbers

I am trying to find if two phone numbers are same or not (Two same phone number may not be in the same format, as +919998245345 is same as 9998245345 and 99982 45345)
For this, you can use contains() dart string method. I have marked the trailing statement as bold, cos, it applies on the String. Make sure you get the number in String format, or convert it to String and then perform the operation.
Alogrithm
Convert the number to be compared to String, or get the number as String
Remove all the white spaces using this code, your_phone_number_variable.replaceAll(new RegExp(r"\s+"), ""). So that every number should be having no white spaces in between for smooth operation
Use contains() like this, number1.contains(number2)
Code
// this is a comparision between +919998245345 and other numbers
// you can play around and get what you want
void main() {
var _inputPhone = "+919998245345";
var _checkPhone = "9998245345";
var _anotherCheck = "99982 45345";
// checking that white space removal works or not
print(_anotherCheck.replaceAll(new RegExp(r"\s+"), ""));
// I have just removed the spaces from the number which had the white
// space, you can store the value using this code for every data
// for unknown data coming from server side or user side
_anotherCheck = _anotherCheck.replaceAll(new RegExp(r"\s+"), "");
if(_inputPhone.contains(_anotherCheck)){
print('99982 45345 and +919998245345 are same');
}
if(_inputPhone.contains(_checkPhone)){
print('9998245345 and +919998245345 are same');
}
}
Output
9998245345
99982 45345 and +919998245345 are same
9998245345 and +919998245345 are same
void main() {
print(isSame('9998245345', '+91999824 5345'));
}
bool isSame(String number1, String number2) {
number1 = number1.replaceAll(' ', '');
number2 = number2.replaceAll(' ', '');
int len1 = number1.length;
int len2 = number2.length;
number1 = number1.substring(len1-10, len1);
number2 = number2.substring(len2-10, len2);
return number1 == number2;
}
I think this is the simple and best solution to chnage format of phone
String changeFormat(String phone) {
phone = phone.replaceAll(" ", "");
if (phone.startsWith("+")) {
return "0" + phone.substring(3);
} else {
return phone;
}
}

Swift Type 'string.index' has no subscript members

I'm currently converting C++ code to Swift and I've gotten stuck on one part. The parameter passed into the function is a string and the area where I'm stuck is when attempting to set a variable based on the second to last character of a string to check for a certain character.
The error shows up on this line:
line[i-1]
I've tried casting this value to an Int but this didn't work:
Int(line[i - 1])
I've also tried to see if the string's startIndex function which takes a Int would work but it didn't:
line.startIndex[i - 1]
Here is the full function:
func scanStringForSpecificCharacters(line: String){
var maxOpen: Int = 0;
var minOpen: Int = 0;
minOpen = 0;
maxOpen = 0;
var i = 0
while i < line.characters.count {
for character in line.characters {
//var c: Character = line[i];
if character == "(" {
maxOpen += 1;
if i == 0 || line[i - 1] != ":" {
minOpen += 1;
}
}
else if character == ")"{
minOpen = max(0,minOpen-1);
if i == 0 || line[i-1] != ":"{
maxOpen -= 1;
}
if maxOpen < 0{
break;
}
}
}
if maxOpen >= 0 && minOpen == 0{
print("YES")
}else{
print("NO")
}
}
}
Strings in Swift aren't indexed collections and instead you can access one of four different views: characters, UTF8, UTF16, or unicodescalars.
This is because Swift supports unicode, where an individual characters may actually be composed of multiple unicode scalars.
Here's a post that really helped me wrap my head around this: https://oleb.net/blog/2016/08/swift-3-strings/
Anyway, to answer you question you'll need to create an index using index(after:), index(before:), or index(_, offsetBy:).
In your case you'd want to do something like this:
line.index(line.endIndex, offsetBy: -2) // second to last character
Also, you'll probably find it easier to iterate directly using a String.Index type rather than Int:
let line = "hello"
var i = line.startIndex
while i < line.endIndex {
print(line[i])
i = line.index(after: i)
}
// prints ->
// h
// e
// l
// l
// o
Working with Strings in Swift was changed several times during it's evolution and it doesn't look like C++ at all. You cannot subscript string to obtain individual characters, you should use index class for that. I recommend you read this article:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html
As already pointed out in the other answers, the compiler error
is caused by the problem that you cannot index a Swift String with
integers.
Another problem in your code is that you have a nested loop which is
probably not intended.
Actually I would try to avoid string indexing at all and only
enumerate the characters, if possible. In your case, you can
easily keep track of the preceding character in a separate variable:
var lastChar: Character = " " // Anything except ":"
for char in line.characters {
if char == "(" {
maxOpen += 1;
if lastChar != ":" {
minOpen += 1;
}
}
// ...
lastChar = char
}
Or, since you only need to know if the preceding character is
a colon:
var lastIsColon = false
for char in string.characters {
if char == "(" {
maxOpen += 1;
if !lastIsColon {
minOpen += 1;
}
}
// ...
lastIsColon = char == ":"
}
Another possible approach is to iterate over the string and a shifted
view of the string in parallel:
for (lastChar, char) in zip([" ".characters, line.characters].joined(), line.characters) {
// ...
}
As others have already explained, trying to index into Swift strings is a pain.
As a minimal change to your code, I would recommend that you just create an array of the characters in your line up front:
let linechars = Array(line.characters)
And then anywhere you need to index into the line, use linechars:
This:
if i == 0 || line[i-1] != ":" {
becomes:
if i == 0 || linechars[i-1] != ":" {

Javascript First letter uppercase restlower of two lines "."

I want to first letter to be in upper case other in lower. But after ".", it must be upper again..
function firstToUpperCase( str ) {
return str.substr(0, 1).toUpperCase() + str.substr(1);
}
var str = 'prompt("Enter text to convert: ")
var Upcase = firstToUpperCase( str );
document.write(Upcase);
Here's a simplistic answer based on what you provided. It does not take whitespace into account following the period since you didn't mention that in the specs.
function firstToUpperCase(str) {
var parts = str.split(".");
for (i = 0; i < parts.length; i++) {
parts[i] = parts[i].substring(0, 1).toUpperCase() + parts[i].substring(1).toLowerCase();
}
return parts.join(".");
}
If you're trying to deal with sentences, something like this might be a little better, though it does not preserve exact whitespace:
function firstToUpperCase(str) {
var parts = str.split(".");
for (i = 0; i < parts.length; i++) {
sentence = parts[i].trim();
parts[i] = sentence.substring(0, 1).toUpperCase() + sentence.substring(1).toLowerCase();
}
return parts.join(". ");

C sharp delimiter

In a given sentence i want to split into 10 character string. The last word should not be incomplete in the string. Splitting should be done based on space or , or .
For example:
this is ram.he works at mcity.
now the substring of 10 chars is,
this is ra.
but the output should be,
this is.
Last word should not be incomplete
You can use a regular expression that checks that the character after the match is not a word character:
string input = "this is ram.he";
Match match = Regex.Match(input, #"^.{0,10}(?!\w)");
string result;
if (match.Success)
{
result = match.Value;
}
else
{
result = string.Empty;
}
Result:
this is
An alternative approach is to build the string up token by token until adding another token would exceed the character limit:
StringBuilder sb = new StringBuilder();
foreach (Match match in Regex.Matches(input, #"\w+|\W+"))
{
if (sb.Length + match.Value.Length > 10) { break; }
sb.Append(match.Value);
}
string result = sb.ToString();
Not sure if this is the sort of thing you were looking for. Note that this could be done a lot cleaner, but should get you started ... (may want to use StringBuilder instead of String).
char[] delimiterChars = { ',', '.',' ' };
string s = "this is ram.he works at mcity.";
string step1 = s.Substring(0, 10); // Get first 10 chars
string[] step2a = step1.Split(delimiterChars); // Get words
string[] step2b = s.Split(delimiterChars); // Get words
string sFinal = "";
for (int i = 0; i < step2a.Count()-1; i++) // copy count-1 words
{
if (i == 0)
{
sFinal = step2a[i];
}
else
{
sFinal = sFinal + " " + step2a[i];
}
}
// Check if last word is a complete word.
if (step2a[step2a.Count() - 1] == step2b[step2a.Count() - 1])
{
sFinal = sFinal + " " + step2b[step2a.Count() - 1] + ".";
}
else
{
sFinal = sFinal + ".";
}