Convert number string from any language while preserving leading zeros - regex

I have a number string that is in Arabic language, I want to convert it to English, I use this:
let arabicPhoneNumber = "٠١٠١٢٣٤٥٦٧٨٩"
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "EN")
if let number = formatter.number(from: arabicPhoneNumber)?.stringValue {
print(number) //deletes leading zero
}
the problem is it deletes the leading zero and I want to preserve it as this is a phone number. is there a way to convert phone number string from Arabic to English without losing leading zeros ??

Instead of converting the string to a number, you can do a "transliteration" to the Latin script, using CFStringTransform() from the Foundation library:
let arabicPhoneNumber = "٠١٠١٢٣٤٥٦٧٨٩"
// We need a CFMutableString and a CFRange:
let cfstr = NSMutableString(string: arabicPhoneNumber) as CFMutableString
var range = CFRange(location: 0, length: CFStringGetLength(cfstr))
// Do the transliteration (this mutates `cfstr`):
CFStringTransform(cfstr, &range, kCFStringTransformToLatin, false)
// Convert result back to a Swift string:
let phoneNumber = cfstr as String
print(phoneNumber) // 010123456789
This preserves all digits as well as possible separators.
Remark: The above example (from the question) contains "Arabic Indic" digits, for example ١ = U+0661 = "ARABIC-INDIC DIGIT ONE".
These are correctly transliterated on macOS 10.12 and iOS 10.
On earlier OS versions,
CFStringTransform(cfstr, &range, kCFStringTransformLatinArabic, true)
CFStringTransform(cfstr, &range, kCFStringTransformStripCombiningMarks, false)
worked correctly in my tests to convert arabic digits to latin.

swift 4.0
func convertToEnDigits(_ digits: String) -> String {
// We need a CFMutableString and a CFRange:
let cfstr = NSMutableString(string: digits) as CFMutableString
var range = CFRange(location: 0, length: CFStringGetLength(cfstr))
// Do the transliteration (this mutates `cfstr`):
CFStringTransform(cfstr, &range, kCFStringTransformToLatin, false)
// Convert result back to a Swift string:
return (cfstr as String)
}

Related

how to choose a password contains at least eight characters,Include numbers and letters,Sequence numbers are not,Do not repeat numbers

I want to choose a password for the user to have at least 8 characters in the password he chooses, and also the number of letters, and that the duplicate numbers should not be sequential numbers when they want to write the password.
This called NSRegularExpression, in the first you need to declare the regular expression string like this:
let langRexEx = "^[a-z.]+$"
Then create a function to check the string with the regular expression. For example just English chars and dot:
func verifyLanguage(value: String) -> Bool {
var returnValue = true
let langRexEx = "^[a-z.]+$" // just chars and dot
do {
let regex = try NSRegularExpression(pattern: langRexEx)
let nsString = value as NSString
let results = regex.matches(in: value, range: NSRange(location: 0, length: nsString.length))
if results.count == 0
{
returnValue = false
}
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
returnValue = false
}
return returnValue
}
Important note: string of regular is hard to find.

Swift3: How to write a String with comma?

Why is the "2,78" String not possible?
func action1()
{
time1 += 2,78
lbltime.text = String(time1)
}
If you want a localized representation of a number, use a NumberFormatter:
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
let x = Float.pi
if let string = formatter.string(for: x) {
print("string:", string)
}
On device with, for example, with German locale with , as decimal separator, that will report:
string: 3,14
But for locales that use a . for the decimal separator, it will report:
string: 3.14

Regex for decimal number and blank Swift

I want a regex in swift matches all decimal numbers and integers, the requirement is following:
Reject these non-numbers:
. (single decimal point)
2.2.2 (two or more decimal points in any order)
-. (negative decimal point)
+. (plus decimal point)
(empty string)
Any help appreciated.
Instead of a regex, why not just try converting the String to a Float. You can put the following in a Swift playground to see that it works:
func isNumber(s: String) -> Bool {
return Float(s) != nil
}
// Your criteria
isNumber(".") // false
isNumber("2.2.2") // false
isNumber("-.") // false
isNumber("+.") // false
isNumber("") // false
// Validity check
isNumber("2.2") // true
isNumber("2") // true
isNumber("-2") // true
If validating user input, rather a regex, why not just try converting the String to a number user NSNumberFormatter. This gets you out of writing regex and handles international formats, too (e.g. in Germany, they enter 2.3 as 2,3):
let numberFormatter: NSNumberFormatter = {
let formatter = NSNumberFormatter()
formatter.numberStyle = .DecimalStyle
return formatter
}()
func isNumber(s: String) -> Bool {
return numberFormatter.numberFromString(s) != nil
}

Dart how to add commas to a string number

I'm trying to adapt this:
Insert commas into number string
to work in dart, but no luck.
either one of these don't work:
print("1000200".replaceAllMapped(new RegExp(r'/(\d)(?=(\d{3})+$)'), (match m) => "${m},"));
print("1000300".replaceAll(new RegExp(r'/\d{1,3}(?=(\d{3})+(?!\d))/g'), (match m) => "$m,"));
Is there a simpler/working way to add commas to a string number?
You just forgot get first digits into group. Use this short one:
'12345kWh'.replaceAllMapped(RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},')
Look at the readable version. In last part of expression I added checking to any not digit char including string end so you can use it with '12 Watt' too.
RegExp reg = RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))');
String Function(Match) mathFunc = (Match match) => '${match[1]},';
List<String> tests = [
'0',
'10',
'123',
'1230',
'12300',
'123040',
'12k',
'12 ',
];
for (String test in tests) {
String result = test.replaceAllMapped(reg, mathFunc);
print('$test -> $result');
}
It works perfectly:
0 -> 0
10 -> 10
123 -> 123
1230 -> 1,230
12300 -> 12,300
123040 -> 123,040
12k -> 12k
12 -> 12
import 'package:intl/intl.dart';
var f = NumberFormat("###,###.0#", "en_US");
print(f.format(int.parse("1000300")));
prints 1,000,300.0
check dart's NumberFormat here
The format is specified as a pattern using a subset of the ICU formatting patterns.
0 A single digit
# A single digit, omitted if the value is zero
. Decimal separator
- Minus sign
, Grouping separator
E Separates mantissa and expontent
+ - Before an exponent, to say it should be prefixed with a plus sign.
% - In prefix or suffix, multiply by 100 and show as percentage
‰ (\u2030) In prefix or suffix, multiply by 1000 and show as per mille
¤ (\u00A4) Currency sign, replaced by currency name
' Used to quote special characters
; Used to separate the positive and negative patterns (if both present)
Try the following regex: (\d{1,3})(?=(\d{3})+$)
This will provide two backreferences, and replacing your number using them like $1,$2, will add commas where they are supposed to be.
Let's take the example amount 12000. now our expected amount should be 12,000.00
so, the solution is
double rawAmount = 12000;
String amount = rawAmount.toStringAsFixed(2).replaceAllMapped(RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},');
or if you don't want to add .00 then, we just need to use toString() instead of toStringAsFixed().
String amount = rawAmount.toString().replaceAllMapped(RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},');
extension on int {
String get priceString {
final numberString = toString();
final numberDigits = List.from(numberString.split(''));
int index = numberDigits.length - 3;
while (index > 0) {
numberDigits.insert(index, ',');
index -= 3;
}
return numberDigits.join();
}
}
because in case of type double, the output will change based on the way, so check them.
If you need to format integer then any way works.
//1233.45677 => 1,233.4567
String num='1233.45677';
RegExp pattern = RegExp(r'(?<!\.\d*)(\d)(?=(?:\d{3})+(?:\.|$))');
String Function(Match) replace = (m) => '${m[1]},';
print(num..replaceAllMapped(pattern, replace));
//1233.45677 => 1,233.456,7
String num='1233.45677';
pattern = RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))');
String Function(Match) replace = (m) => '${m[1]},';
print(num..replaceAllMapped(pattern, replace));
//1233.45677 => 1,233.46
//after import intl package, to be able to use NumberFormat
String num='1233.45677';
var f = NumberFormat("###,###.0#", "en");
print(f.format(double.parse()));
if the number is in String type.
//in case of int data type
int.parse(num);
//in case of double data type
double.parse(num);

How to parse a string of hex into ascii equivalent in Swift 2

In swift 2 what is the best way to go about turning strings of hex characters into their ascii equivalent.
Given
let str1 = "0x4d 0x4c 0x4e 0x63"
let str2 = "4d 4c 4e 63"
let str3 = "4d4c4e63"
let str4 = "4d4d 4e63"
let str5 = "4d,4c,4e,63"
we would like to run a function (or string extension) that spits out: 'MLNc' which is the ascii equivalent of the hex strings
Pseudo Code:
Strip out all "junk", commas spaces etc
Get "2 character chunks" and then convert these characters into the int equivalent with strtoul
build an array of characters and merge them into a string
Partial Implementation
func hexStringtoAscii(hexString : String) -> String {
let hexArray = split(hexString.characters) { $0 == " "}.map(String.init)
let numArray = hexArray.map{ strtoul($0, nil, 16) }.map{Character(UnicodeScalar(UInt32($0)))}
return String(numArray)
}
Is this partial implementation on the correct path? And if so, how is the best way to handle the chunking
Using regular expression matching is one possible method to extract the
"hex numbers" from the string.
What you are looking for is an optional "0x", followed by exactly
2 hex digits. The corresponding regex pattern is "(0x)?([0-9a-f]{2})".
Then you can convert each match to a Character and finally concatenate
the characters to a String, quite similar to your "partial implementation". Instead of strtoul() you can use the UInt32
initializer
init?(_ text: String, radix: Int = default)
which is new in Swift 2.
The pattern has two "capture groups" (encloses in parentheses),
the first one matches the optional "0x", and the second one matches
the two hex digits, the corresponding range can be retrieved with
rangeAtIndex(2).
This leads to the following implementation which can handle all
your sample strings:
func hexStringtoAscii(hexString : String) -> String {
let pattern = "(0x)?([0-9a-f]{2})"
let regex = try! NSRegularExpression(pattern: pattern, options: .CaseInsensitive)
let nsString = hexString as NSString
let matches = regex.matchesInString(hexString, options: [], range: NSMakeRange(0, nsString.length))
let characters = matches.map {
Character(UnicodeScalar(UInt32(nsString.substringWithRange($0.rangeAtIndex(2)), radix: 16)!))
}
return String(characters)
}
(See Swift extract regex matches for an explanation for the conversion to NSString.)
Note that this function is quite lenient, it just searches for
2-digit hex strings and ignores all other characters, so this
would be accepted as well:
let str6 = "4d+-4c*/4e😈🇩🇪0x63"
Update for Swift 5.1:
func hexStringtoAscii(_ hexString : String) -> String {
let pattern = "(0x)?([0-9a-f]{2})"
let regex = try! NSRegularExpression(pattern: pattern, options: .caseInsensitive)
let nsString = hexString as NSString
let matches = regex.matches(in: hexString, options: [], range: NSMakeRange(0, nsString.length))
let characters = matches.map {
Character(UnicodeScalar(UInt32(nsString.substring(with: $0.range(at: 2)), radix: 16)!)!)
}
return String(characters)
}