I have a list (string) of phone numbers from any country.
for example:
var items = new List<string> { "+989302794433", "009891234599882", "+391234567890", "00336615551212"};
at first, I think that every country code length is exactly two number, for example(33: France, 39: Italy, 98: Iran , ...).
using libphonenumber library, you must be pass the regCode for parsing. and because of (in my scenario) I get the list of string(mobile number), then I must be separate country code from number.
foreach (var item in items)
{
int countryCode = 0;
var number = "";
if (item.StartsWith("+"))
{
countryCode = int.Parse(item.Substring(1, 2));
number = item.Substring(3);
}
else if (item.StartsWith("00"))
{
countryCode = int.Parse(item.Substring(2, 2));
number = item.Substring(4);
}
var regCode = phoneUtil.GetRegionCodeForCountryCode(countryCode);
var numberWithRegCode = phoneUtil.Parse(number, regCode);
if (!phoneUtil.IsValidNumber(numberWithRegCode)) continue;
//else ...
}
this code fine worked just for country codes that their length is two numbers!
but after a little time , I knew that some country code length is one number( for example, US: 1) and even three number!.
now, is exists any way using libphonenumber library (or other solutions) to solve this issue?
thanks a lot
The libphonenumber library can find country codes by itself as long as the number starts with a +. So, just replace double zeros at the beginning of a number with a plus. And then let the library decide whether the number is valid on its own.
libphonenumber will on its own know which is the country code following the plus sign (it internally has a list of all the codes) and then apply the rules according to the correct country to decide whether the number is valid.
bool IsValidNumber(string aNumber)
{
bool result = false;
aNumber = aNumber.Trim();
if (aNumber.StartsWith("00"))
{
// Replace 00 at beginning with +
aNumber = "+" + aNumber.Remove(0, 2);
}
try
{
result = PhoneNumberUtil.Instance.Parse(aNumber, "").IsValidNumber;
}
catch
{
// Exception means is no valid number
}
return result;
}
You can use date ftom this package https://www.npmjs.com/package/dialcodes
Related
I am trying to make software to search for byte patterns, I have many bin files and many patterns to search. If the pattern exists on the file. it will represent it on CheckedListBox with a specific name . and if the checked box is checked for a particular one , it will replace the pattern with 0000000000 on the saved file.
For example, I have this pattern to search (note that I have more than 100 patterns to search):
{"2004940101000078", "3004940101000078", "3E04940101000028", .... ,.... }
Open the bin file by OpenFileDialog
Covert the file to byteArray
Search for the patterns
put the result on checkedlist Box
(2004940101000078 = P0420) (3004940101000078 = P0430) (3E04940101000028 =P043E),note P0420 is the name that i want to put on the checkedbox:
DTC
Description
Checkedbox P0420
Catalyst System Efficiency Below Threshold Bank1
Checkedbox P0430
Catalyst System Efficiency Below Threshold Bank2
Checkedbox P043E
EvaporativeEmissionSystemLeakDetectionReferenceOrificeLowFlow
If I want to delete the code P0420 , checkbox P0420 replace 2004940101000078 with 0000000000000000 and save it to a new bin file
I tried with this code to search for the patterns, but its give the offset position of the pattern only. please this code-only example and part of my codes.if you have a solution or other code or way. please help, I am new in C#
string hex2 = BitConverter.ToString(byteArray).Replace("-", string.Empty);
string[] patterns = {"2004940101000078", "3004940101000078", "3E04940101000028" };
foreach (string p in patterns)
{
int i = 0;
int indice = 0;
// teminate loop when no more occurrence is found;
while (indice != -1)
{
// index if the pattern is found AFTER i position, -1 if not
indice = hex2.IndexOf(p, i);
i = indice + 0; // skip the pattern occurrence itself
int indexxx = (i / 2);
//Transform the index into hexadecimal
string outputHex = int.Parse(indexxx.ToString()).ToString("X");
//Output the index as an hexadecimal offset address
MessageBox.Show("0x" + outputHex);
break;
}
}
thank you
You are checking the hex string versions of the byte arrays. This means
You can easily use IndexOf to find a match - great
You will use 4 times as much memory (one byte = two 16-bit chars)
You can have "false positives": searching for "1234" will find it in "512346" - you will have to check whether that can be a problem, or better, just guard against it (keep searching if you find an odd index)
If you want to remember where the match was and link it to certain buttons, don't use a List<string> but a List<PatternMatch> where PatternMatch is:
public class PatternMatch
{
public string HexPattern {get;set;} // the pattern to search for
public int HexIndex {get;set;} = -2; // the index where it was found, -1=not found, -2=not searched yet
public string Name {get;set;} // the button name, like P0420, P0430
public bool ToErase {get;set;} // whether to erase the matched pattern from the input
}
and then something like:
// the source to search in
string hex2 = BitConverter.ToString(byteArray).Replace("-", string.Empty);
// your patterns and button names
List<PatternMatch> patterns = new List<PatternMatch>();
patterns.Add(new PatternMatch { HexPattern = "2004940101000078", Name = "P0420" });
patterns.Add(new PatternMatch { HexPattern = "3004940101000078", Name = "P0430" });
patterns.Add(new PatternMatch { HexPattern = "3E04940101000028", Name = "P043E" });
// etc
foreach(var pattern in patterns)
{
// initialise search position
pattern.HexIndex = -1;
do
{
// try and find next match
pattern.HexIndex = hex2.IndexOf(pattern.HexPattern, pattern.HexIndex+1);
// repeat while there was something found, but at an odd index (false positive)
} while (pattern.HexIndex != -1 && index % 2 == 1);
// NB: in the original byte[] use half of pattern.HexIndex
if (pattern.HexIndex == -1)
Debug.WriteLine($"pattern {pattern.HexPattern} not found");
else
Debug.WriteLine($"pattern {pattern.HexPattern} found at byte index {pattern.HexIndex/2}");
}
Then you can use that "patterns" list to match/fill your checkboxes, using pattern.Name to find the corresponding checkbox.
When the checkbox is checked, set the corresponding pattern.ToErase to true.
You can do it by handling the "checked changed" event.
Assuming winforms with CheckBox. you can set the Tag property to the name (like "P0420"). Then you can find out what pattern this checkbox belongs to, independent of what you display.
Then you will need to handle the Click event for all checkboxes using one method:
private void PatternCheckbox_Click(object sender, System.EventArgs e)
{
var cb = (CheckBox)sender;
var name = (string)cb.Tag; // The type of Tag is 'object', so you need a cast
var pattern = patterns.Single(p => p.Name == name); // find the corresponding one
pattern.ToErase = cd.Checked; // set 'ToErase to match the checkbox state
}
Or when you use a CheckedListBox then, in your Save method, use its CheckedItems to get the checked items so you can set the corresponding ToErase flag:
// TODO fix some names to match your code
foreach(object itemChecked in checkedListBox1.CheckedItems)
{
// TODO cast 'itemChecked' to the correct type
var myitem = (MyItem)itemChecked;
// TODO get its name ("P0420" etc)
string name = myitem.Name;
var pattern = patterns.Single(p => p.Name == name); // find the corresponding pattern
pattern.ToErase = true; // the CheckedItems only returns checked items (and indeterminate)
}
Then you can start to perform the erasures.
When the user clicks "Save", you can loop through the patterns and see which have set ToErase to true. Then you can replace the corresponding HexPattern at the HexIndex that was found with zeroes.
Tip: new string('0', HexPattern.Length) has exactly enough 0's to cover that pattern.
This should do the erasures:
// process the marked patterns that correspond to a real match
foreach (var toErase in patterns.Where(p => p.ToErase && p.HexIndex >= 0))
{
// first remove the old pattern, then insert 0's
// (Replace would replace all occurrences, not just the one at the index you found)
hex2 = hex2.Remove(toErase.HexIndex, toErase.HexPattern.Length)
.Insert(toErase.HexIndex, new string('0', toErase.HexPattern.Length));
}
I am not even sure how to phrase this question so I apologize in advance. I have a form used by our QA. it requires input of serial numbers - a lot of them (sometimes hundreds). I have two text boxes on the form for lower and upper numbers in the range (doesn't have to be this way but it is my best guess). I know how to to do this if it were just integers (see code below) but that is not the only format.Examples of the format could include a date code ("170508/1234") or could include alpha characters (ABC1234). there is a wide variety of formats but in every case, I want to find the range from the last set of numbers (typically last four digits - Like "170508/1234 170508/1235... and ABC1234 ABC1235 ... not to exclude 1234 1235 ....).
Thank you in advance
private void btnSN_Click(object sender, EventArgs e)
{
int from = Convert.ToInt32(txtSnStart.Text.Trim());
int to = Convert.ToInt32(txtSnEnd.Text.Trim());
for (int i = from; i <= to; i++)
{
txtSN.Text += i.ToString() +" ";
}
You can make use of RexEx for this, the RegEx expression below should match any number of digits at the end.:
(\d+)$
Here is the modified code:
// find the group of digits at end of entered text
var fromMatch = Regex.Match(txtSnStart.Text.Trim(), #"(\d+)$");
int from = Convert.ToInt32(fromMatch.Groups[1].Value);
// strip the matched digit group from entered text to get the prefix
string prefix = txtSnStart.Text.Trim().SubString(0, txtSnStart.Text.Trim().LastIndexOf(from.ToString()));
var toMatch = Regex.Match(txtSnEnd.Text.Trim(), #"(\d+)$");
int to = Convert.ToInt32(toMatch.Groups[1].Value);
for (int i = from; i <= to; i++)
{
// combine the prefix and range value
txtSN.Text += string.Format("{0}{1} ", prefix, i.ToString());
}
This problem becomes easier if you break it into smaller pieces.
This will become especially important once it becomes apparent that one small part of the problem might become more complex.
The inputs are a prefix, a number to begin the range, and a number to end the range. Given that, here's a class with a function to return those strings:
public class StringRangeCreator
{
public IEnumerable<string> CreateStringRange(
string prefix, int rangeStart, int rangeEnd)
{
if (rangeStart > rangeEnd) throw new ArgumentException(
$"{nameof(rangeStart)} cannot be greater than {nameof(rangeEnd)}");
return Enumerable.Range(rangeStart, (rangeEnd-rangeStart) + 1)
.Select(n => prefix + n);
}
}
Enumerable.Range creates a range of numbers. The Select takes that range and returns a set of strings consisting of the prefix concatenated with the number in the range.
And a unit test to make sure it works:
[TestClass]
public class DetermineRangeFromLastFourCharacters
{
[TestMethod]
public void ReturnsExpectedRangeOfStrings()
{
var result = new StringRangeCreator().CreateStringRange("abc", 1, 10).ToList();
Assert.AreEqual(10, result.Count);
Assert.AreEqual("abc1", result[0]);
Assert.AreEqual("abc10", result[9]);
}
}
But if these are serial numbers then you maybe you don't want ABC8, ABC9, ABC10. You might want ABC08, ABC09, ABC10. All the same length.
So here's the modified class. I'm guessing a little at what the expected behavior might be. It lets you specify an optional minimum number of digits so that you can pad accordingly:
public class StringRangeCreator
{
public IEnumerable<string> CreateStringRange(
string prefix, int rangeStart, int rangeEnd, int minimumDigits = 1)
{
if (rangeStart > rangeEnd) throw new ArgumentException(
$"{nameof(rangeStart)} cannot be greater than {nameof(rangeEnd)}");
return Enumerable.Range(rangeStart, (rangeEnd-rangeStart) + 1)
.Select(n => prefix + n.ToString("0").PadLeft(minimumDigits, '0'));
}
}
And another unit test:
[TestMethod]
public void PadsNumbersAccordingToParameter()
{
var result = new StringRangeCreator().CreateStringRange("abc", 999, 1001, 3).ToList();
Assert.AreEqual(3, result.Count);
Assert.AreEqual("abc999", result[0]);
Assert.AreEqual("abc1001", result[2]);
}
Some other scenarios you might want to account for are negative numbers or extremely large ranges.
Now that the problem of creating the result set is separated into a class with simple inputs and outputs that you can test, what remains is to take the input from the form and break it down into these inputs. That might include making sure that both strings have the same prefixes and making sure that the last parts of the strings are numbers.
But the whole thing will be a little simpler once it's not all in one big method. That also makes it easier to change when you realize something different about how you want it to work. Validating your input can be one step, and then getting the results can be another.
The unit tests help because you don't want to have to debug the whole thing to see if it works. Enumerable.Range didn't work the way I thought it did, so I had to fix a bug. It was easy to find and fix with the unit tests. It would have been harder if I had to run a whole app and then step through it in the debugger.
Recently I've been told to change one validation towards a database to a new database in a C# application. Instead of the old database I would be using the new one.
The problem is that I can't run the app. I need to publish it so the guys that uses it give me their feedback.
So I decided to share this part of the code that I added.
Not changed, but added. This is something new and a potential thing that can go wrong.
Hopefully someone with more experience will tell me how much my code sucks or if it looks OK.
Thing is... the old database has an int value in a column and the new one has a nvarchar(5).
So I made this to convert the old one in a new one.
string ConvertIDToReg(string kairosID)
{
double n;
if (!Double.TryParse(Convert.ToString(kairosID),
System.Globalization.NumberStyles.Any,
System.Globalization.NumberFormatInfo.InvariantInfo, out n))
{
return "0";
}
char[] regID = kairosID.ToCharArray();
if (regID.Length > 4)
{
return "0";
}
if (reg.Length == 3)
{
regID[4] = regID[3];
regID[3] = regID[2];
regID[2] = regID[1];
regID[1] = regID[0];
regID[0] = "0";
}
return regID.ToString();
}
This is how it should work:
The old ID is something like "1234" but the new one is a 5 char max ID with a 0 in the beginning like "01234" (if the 5th number is not occupied). So basically I want to be able to put a 0 in the beginning if there isn't a 5th number.
If the number exceeds the 5 digits I want to return a 0 as the whole string (this will be handled later)
If the number is not a number (i.e "123ABC") return a 0 all the same.
Should this compile or even work?
What about efficiency? This will run several times. Any help to make this faster will do.
No, this won't compile. You misspelled your second regID (forgot the 'ID'), and are assigning a string to a char at regID[0] = "0";
Change that and it will compile, then blow up when you run it, when regID.Length= 3, because you're trying to access index 3 and 4, which it clearly will not have.
This should do what you're wanting:
string ConvertIDToReg(string kairosID)
{
if (kairosID.Length > 4 || kairosID.Any(c => !char.IsDigit(c)))
return "0";
return kairosID.PadLeft(5, '0');
}
if it's longer than 4 characters or if any character is not a digit, return a zero as a string ("0"). Else return the ID padded to 5 digits. About as simple as i can make it I think. No need to parse it as an int even.
This code should work:
private string ConvertIntToChar(string numValue)
{
int result = 0;
if (int.TryParse(numValue, out result) == false || numValue.Length > 4)
{
return "0";
}
return numValue.PadLeft(5, '0');
}
If value is not of 4 characters then it will add number of "0" required to make the string length equal to 5.
If the string is always some form of an integer i would approach the problem as such. and you wanted to keep every thing else the same. the "D5" tells the ToString method to 0 pad the string so that it is always 5 digits but retains the same numerical value.
string ConvertIDToReg(string kairosID)
{
int id;
if (!Int32.TryParse(kairosID, out id) || id > 9999)
{
return "0";
}
return id.ToString("D5");
}
I am trying to count how many zeroes are a before a decimal.
private void textBox1_TextChanged(object sender, EventArgs e)
{
decimal x = 0;
if (Decimal.TryParse(textBox1.Text, out x))
{
var y = 1000000;
var answer = x * y;
displayLabel2.Text = (x.ToString().Replace(".", "").TrimStart(new Char[] { '0' }) + "00").Substring(0, 2);
}
else
{
displayLabel2.Text = "error";
}
}
When I plug in (lets say) 7.2 I get an output that displays 72, which is what I want. Now I need another display. That initial 7.2 is being multiplied by 1000000. So the quotent of that would be 7,200,000.00. Now I need to some how count the 5 zeroes before the decimal point and display 5 for that. Then if I were to do .72. My Quotent would be 720,000.00. And I would need to display 4, for the 4 zeroes. And so on. Then I need to output that number to displayLabel5.Text
Here's a one line Linq you could try to count zeroes before the decimal. You can Split() first by the decimal then perform a Where().Count() to get the number of zeros.
using System;
using System.Linq;
public class Program
{
public static void Main()
{
string myString = (720000.00).ToString();
Console.WriteLine(myString.Split('.')[0].Where(d => d == '0').Count());
}
}
Results:
4
Demo
Quick and dirty code so be careful, but AFAIK this is the fastest way to do it.
// Input assuming you've sanitised it
string myInputString = "720000.00";
// Remove the decimals
myInputString = myInputString.Substring(0, myInputString.IndexOf("."));
// The count
int count = 0;
// Loop through and count occurrences
foreach (char c in myInputString)
{
if (c == "0")
{
count++;
}
}
Count is now 4.
Guarantee you this is faster than Regex ;-)
Edit: Sorry for the multiple edits, it's been a long day. Need coffee.
use a regular expression to find all the zeros before the period, then get the string length of that match.
Regex regex = new Regex(#"(0+)\.?");
string value1 = "7,200,000.00";
value1 = value1.Replace(",",""); //get rid of the commas
Match match = regex.Match(value1);
if (match.Success)
{
Console.WriteLine(match.Value.Length);
}
As always test the code because I wrote it just now here in this little text box and not in actual visual studio where I could compile and test it myself. But this should at least illustrate the methodology.
Edit:
slight tweak to the regex to account for the possibility that the number will not display a decimal point at all.
I have a program that generates a control number. Control number contains 13 numbers. The first 3 numbers is generated if the user is a maritime education, it is 100, but if the user is a general education, it is 101, then the following 5 numbers is a random numbers. Then the last 5 digits is the ID number of the user.
Code :
Random rand = new Random();
int startingDigits;
if (CmbEducation.SelectedItem.Equals("Maritime Education"))
{
startingDigits = 100;
string IdNumber = TxtIDnum.Text;
string controlNumber = string.Format("{0}{1}{2}",
startingDigits, rand.Next(10000, 99999).ToString(), IdNumber);
TxtControlNum.Text = controlNumber;
}
else if (CmbEducation.SelectedItem.Equals("General Education"))
{
startingDigits = 101;
string IdNumber = TxtIDnum.Text;
string controlNumber = string.Format("{0}{1}{2}",
startingDigits, rand.Next(10000, 99999).ToString(), IdNumber);
TxtControlNum.Text = controlNumber;
}
My problem is, I want to make an if..else condition. but i want to read the first 3 numbers of the control number how do i do it? Thanks :)
edited :
I am using the control number in another form now for password. So i want to read the first 3 numbers to get if the user is a marine education or a general education.
Now, I am in another form, i just copied the text from the login page where the password is the control number to the textbox in another form. so how do i read first 3 numbers inside a textbox?
Not sure if I'm reading your question correctly, but if all you need is to read the first three digits, just do:
var start = new String(controlNumber.Take(3).ToArray());
or
var start = controlNumber.Substring(0,3);
It's not clear what you mean by "read inside a textbox". Do you want to read them from a textbox? Then try:
TextboxName.Text.Substring(0,3);
If you want to place them in a textbox, use:
TextboxName.Text = controlNumber.Substring(0,3);
Update: I'll give this one more try. This should be self-explanatory, assuming you've got start as above:
if (start.Equals("100"))
{
// Do something
}
else if (start.Equals("101"))
{
// Do something else
}
else
{
// ...take a nap?
}
var controlNumberPrefix = myTextBox.Text.Substring(0, 3);
switch (controlNumberPrefix)
{
case "100":/* Maritime education - do something */ ; break;
case "101":/* Gen education - do something */ ; break;
}
or
var controlNumberPrefix = myTextBox.Text.Substring(0, 3);
if(controlNumberPrefix == "100")
// Do something
else if (controlNumberPrefix =="101")
// Do something
Edit:
Its the same thing with textbox. Just use the Text property of the textbox.