C# string contains all alphabetic characters of another string - c#

I have two strings like this:
string longName = "PRODUCT MANAGER OFFICE";
string shortName = "P.M.O";
I want to validate if longName contains short name alphabetic characters (PMO).
But the short name may be like this:
string shortName = "PMO";
string shortName = "pmo";
string shortName = "pmoff";
All of these short names contain p, m, o, f characters and these are also used in long name.
So I want to math string characters. How can I do this? Should I use regex or another way?

Regex is to heavy and slow for this simple simple task.
string longName = "PRODUCT MANAGER OFFICE";
string shortName = "P.M.O";
public bool ValidateStrings(string longName, string shortName)
{
bool isValid = false;
foreach (var character in shortName)
{
if (Char.IsLetter(character))
{
isValid = longName.Contains<char>(character);
if (!isValid)
{
return false;
}
}
}
return isValid;
}

It's quite easy. Firstly, split the entire string into words :
var text = "PRODUCT MANAGER OFFICE";
string Shortform = "";
var words = text.Split(' ').ToArray();
foreach (string word in words)
{
///Now in the loop, we will get the first character of each word and pass it to the ShortForm variable
Shortform = Shortform + word.Substring(0,1);
}
So, now you have the short form as well, you can easily compare it with the given short form, sample :
if(ShortForm == "abc")
{
}
Hope this helps :)

Try this code...
string str = "PRODUCT MANAGER OFFICE";
string shortname = "P.M.O";
string compareStr = "";
string[] strArry = str.Split(' ');
foreach (string x in strArry)
{
if(x.Trim() != string.Empty)
{
compareStr += x[0];
}
}
//Console.WriteLine(compareStr);
if(compareStr.Equals((shortname.Replace(".", string.Empty)), StringComparison.InvariantCultureIgnoreCase))
{
Console.WriteLine("valid");
}
Demo 01: http://rextester.com/XVCG27648
Demo 02: http://rextester.com/GLSN75240
Demo 03: http://rextester.com/KVTN19152
The above method will not work if you enter 'PMOFF'. If you also want that, you can check the below method. Keep in mind that these both solutions only check the first character of all words. The second method will just ignore other characters.
string str = "PRODUCT MANAGER OFFICE";
string shortname = "P.M.OFF";
int count = 0;
string compareStr = "";
string[] strArry = str.Split(' ');
foreach (string x in strArry)
{
if(x.Trim() != string.Empty)
{
count++;
compareStr += x[0];
}
}
if(compareStr.Equals((((compareStr + " ").Remove(count)).Replace(".", string.Empty)), StringComparison.InvariantCultureIgnoreCase))
{
Console.WriteLine("valid");
}
Demo 04: http://rextester.com/EUIJ88090

It looks like you're matching up abbreviated names to proper names but without any real formatting (PRODUCT MANAGER OFFICE can be pmo or pmoff). So you need to be able to search each character for a match and stop searching when no match is found. You also need to keep track of the last position so that subsequent duplicate characters must match a new position. This makes the assumption that the order matters (pmo matches PRODUCT MANAGER OFFICE but won't match PRODUCT OFFICE MANAGER) and that all characters matter (pmoff matches PRODUCT MANAGER OFFICE but won't match PRODUCT MANAGER OF)
The following will work for all of your sample inputs and some additional test cases for longNames that I added. It's still not bulletproof though. As you can see with these requirements pmo will also match GYPSUM MINING OFFICE because of the P in the first word. Maybe you can tailor it to your needs.
static void Main()
{
var longNames = new string[]
{
"PRODUCT MANAGER OFFICE",
"GYPSUM MINING OFFICE",
"The PRODUCTION of MANAGEMENT for OFFICES",
"PRODUCT PACKING PLANT",
"PRODUCT OFFICE MANAGER",
"PRODUCT MANAGER OF"
};
string shortName = "P.M.Off";
var charsToSearchFor = shortName.ToLower().Where(c => char.IsLetter(c)).ToArray();
foreach (var longName in longNames.Select(longName=>longName.ToLower()))
{
var allCharsFound = true;
var lastMatchPosition = -1;
foreach (var searchChar in charsToSearchFor)
{
var matchPosition = longName.IndexOf(searchChar, lastMatchPosition+1);
if (matchPosition > lastMatchPosition)
{
lastMatchPosition = matchPosition;
}
else if (matchPosition == -1)
{
allCharsFound = false;
break;
}
}
Console.WriteLine($"{longName} : {allCharsFound}");
}
Console.ReadKey();
}
Using P.M.Off as the shortName input, this will output:
PRODUCT MANAGER OFFICE : True
GYPSUM MINING OFFICE : True
The PRODUCTION of MANAGEMENT for OFFICES : True
PRODUCT PACKING PLANT : False
PRODUCT OFFICE MANAGER : False
PRODUCT MANAGER OF: False

Related

String Replace c# for address abbreviation

I have a code for conversion but some address have different result to what is expected.
23 Starling St => 3 Streetarling Street which is wrong and it should be 23 Starling Street
1 St Johns Ct => 1 Street Johns Ct => Correct
This is the code:
private string StreetConversion(string address, Order order)
{
string[] addressList = address.Split(' ');
foreach (string add in addressList)
{
if(add == "pde")
address = address.Replace("pde", "Parade");
if (add == "Pde")
address = address.Replace("Pde", "Parade");
if (add == "Rd")
address = address.Replace("Rd", "Road");
if (add == "rd")
address = address.Replace("rd", "Road");
if (add == "St")
address = address.Replace("St", "Street");
if (add == "st")
address = address.Replace("st", "Street");
}
order.ShipAddress1 = address;
return address;
}
You need to replace given word instead of replacing all occurences of that word in address variable,
private string StreetConversion(string address, Order order)
{
string[] addressList = address.Split(' ');
StringBuilder newAddress = new StringBuilder();
foreach (string add in addressList)
{
if(add.ToLower() == "pde")
newAddress.Append("Parade ");
else if (add.ToLower() == "rd")
newAddress.Append("Road ");
else if (add.ToLower() == "st")
newAddress.Append("Street ");
else
newAddress.Append(add+ " ");
}
order.ShipAddress1 = newAddress.ToString();
return newAddress.ToString();
}
First of all, let's extract model: acronyms and their substitutions
private static Dictionary<string, string> acronyms =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) {
{"pde", "Parade"},
{"rd", "Road"},
{"st", "Street"},
//TODO: Add more pairs if required, say, {"sq", "square"},
};
Then we can easily transform the string address:
using System.Linq;
...
private string StreetConversion(string address, Order order) {
string result = string.Join(" ", address
.Split(' ')
.Select(word => acronyms.TryGetValue(word, out var newWord) ? newWord : word));
order.ShipAddress1 = result;
return result;
}
Step 1: Lets follow "The Single Responsibility Principle" to keep code cleaner and maintainable.
"The Single Responsibility Principle: A class or method should have only a single responsibility."
So you need to take out the following code from the method:
order.ShipAddress1 = address;
Step 2: Your method responsibility should only be converting the street and return it back, and you can reach that in many ways, the following is one of the ways:
private string StreetConversion(string address) {
var newAddress= string.Empty;
foreach (var s in address.Split(' ')) {
newAddress+= (s.ToLower()) switch {
"st" => "Street",
"rd" => "Road",
"pde" => "Parade",
_ => s + " ",
};
}
return newAddress;
}
Step 3: Calling the method
order.ShipAddress1 = StreetConversion(OldAddress);
You can use Regex also to replace the work with another word.
s = Regex.Replace(s, #"\boldVal1\b", "newVal1", RegexOptions.IgnoreCase);
s = Regex.Replace(s, #"\boldVal2\b", "newVal2", RegexOptions.IgnoreCase);

C# How to implement CSV file into this code

Hi I am fairly new to coding, I have a piece of code that searches for a string and replaces it with another string like so:
var replacements = new[]{
new{Find="123",Replace="Word one"},
new{Find="ABC",Replace="Word two"},
new{Find="999",Replace="Word two"},
};
var myLongString = "123 is a long 999 string yeah";
foreach(var set in replacements)
{
myLongString = myLongString.Replace(set.Find, set.Replace);
}
If I want to use a CSV file that contains a lot of words and their replacements, for example, LOL,Laugh Out Loud, and ROFL, Roll Around Floor Laughing. How would I implement that?
Create a text file that looks like (you could use commas, but I like pipes (|)):
123|Word One
ABC|Word Two
999|Word Three
LOL|Laugh Out Loud
ROFL|Roll Around Floor Laughing
Then create a tiny helper class:
public class WordReplace
{
public string Find { get; set; }
public string Replace { get; set; }
}
And finally, call this code:
private static string DoWordReplace()
{
//first read in the data
var fileData = File.ReadAllLines("WordReplace.txt");
var wordReplacePairs = new List<WordReplace>();
var lineNo = 1;
foreach (var item in fileData)
{
var pair = item.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries);
if (pair.Length != 2)
{
throw new ApplicationException($"Malformed file, line {lineNo}, data = [{item}] ");
}
wordReplacePairs.Add(new WordReplace{Find = pair[0], Replace = pair[1]});
++lineNo;
}
var longString = "LOL, 123 is a long 999 string yeah, ROFL";
//now do the replacements
var buffer = new StringBuilder(longString);
foreach (var pair in wordReplacePairs)
{
buffer.Replace(pair.Find, pair.Replace);
}
return buffer.ToString();
}
The result is:
Laugh Out Loud, Word One is a long Word Three string yeah, Roll Around Floor Laughing

Create a list of objects with initialized properties from a string with infos

I have a string that looks like that:
random text 12234
another random text
User infos:
User name : John
ID : 221223
Date : 23.02.2018
Job: job1
User name : Andrew
ID : 378292
Date : 12.08.2017
Job: job2
User name : Chris
ID : 930712
Date : 05.11.2016
Job : job3
some random text
And this class:
class User
{
public string UserName { get; set; }
public string ID { get; set; }
public string Date { get; set; }
public string Job { get; set; }
public User(string _UserName, string _ID, string _Date, string _Job)
{
UserName = _UserName
ID = _ID;
Date = _Date;
Job = _Job;
}
}
And I want to create a List of Users with informations from that string.
I have tried doing that:
List<User> Users = new List<User>();
string Data = (the data above)
string[] lines = Data.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
List<string> UserNames = new List<string>();
List<string> IDs = new List<string>();
List<string> Dates = new List<string>();
List<string> Jobs = new List<string>();
foreach (var line in lines)
{
if (line.StartsWith("User name : "))
{
UserNames.Add(Line.Remove(0, 12));
}
if (Line.StartsWith("ID : "))
{
IDs.Add(Line.Remove(0, 5));
}
if (Line.StartsWith("Date : "))
{
Dates.Add(Line.Remove(0, 7));
}
if (Line.StartsWith("Job : "))
{
Jobs.Add(Line.Remove(0, 6));
}
}
var AllData = UserNames.Zip(IDs, (u, i) => new { UserName = u, ID = i });
foreach (var data in AllData)
{
Users.Add(new User(data.UserName, data.ID, "date", "job"));
}
But I can only combine two lists using this code. Also, I have more than 4 values for each user (the string above was just a short example) .
Is there a better method? Thanks.
Since it seems to be always 4 lines of information you could go in steps of 4 with a loop through the splitted array lines. At each step you would split by colon : and collect the last item, which is the desired value:
EDIT: In this case I would suggets to look for the START of the data.
int startIndex = Data.IndexOf("User name");
EDIT 2:
also ends with another line of text
then you can use LastIndexOf to find the end of the important information:
int endIndex = Data.LastIndexOf("Job");
int lengthOfLastLine = Data.Substring(endIndex).IndexOf(Environment.NewLine);
endIndex += lengthOfLastLine;
and then simply take a SubString from the startindex on until the end
string [] lines = Data.Substring(startIndex, endIndex - startIndex)
.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
List<User> allUsers = new List<UserQuery.User>();
for (int i = 0; i < lines.Length; i += 4)
{
string name = lines[i].Split(':').Last().Trim();
string ID = lines[i + 1].Split(':').Last().Trim();
string Date = lines[i + 2].Split(':').Last().Trim();
string Job = lines[i + 3].Split(':').Last().Trim();
allUsers.Add(new User(name, ID, Date, Job));
}
Ahhh, and you should Trim the spaces away.
This solution should be readable. The hard coded step size of 4 is actually annoying in my solution
Disclaimer: This solution works only as long as the format does not change. If the order of the lines should change, it will return false results
Instead of checking each line to add each of them to a a list, you can create your list of User directly. There you go:
Split by double new line
Split by new line
Build each User
Code:
var users = data.Split(new[] {"\n\n" }, StringSplitOptions.None).Select(lines =>
{
var line = lines.Split(new[] { "\n" }, StringSplitOptions.None);
return new User(line[0].Substring(11), line[1].Substring(4), line[2].Substring(6), line[3].Substring(5));
});
Try it online!
As #Mong Zhu answer, remove everything before and after. A this point, this is another question I wont try to solve. Remove the noise before and after then parse your data.
For a robust, flexible and self-documenting solution that will allow you to easily add new fields, ignore all the extraneous text and also cater for variations in your file format (this seems to be the case with, for example, no space in "ID:" only in the 3rd record), I would use a Regex and some LINQ to return a collection of records as follows:
using System.Text.RegularExpressions;
public class Record
{
public string Name { get; set; }
public string ID { get; set; }
public string Date { get; set; }
public string Job { get; set; }
}
public List<Record> Test()
{
string s = #"User name : John
ID : 221223
Date : 23.02.2018
Job: job1
User name : Andrew
ID : 378292
Date : 12.08.2017
Job: job2
User name : Chris
ID: 930712
Date : 05.11.2016
Job: job3
";
Regex r = new Regex(#"User\sname\s:\s(?<name>\w+).*?ID\s:\s(?<id>\w+).*?Date\s:\s(?<date>[0-9.]+).*?Job:\s(?<job>\w\w+)",RegexOptions.Singleline);
r.Matches(s);
return (from Match m in r.Matches(s)
select new Record
{
Name = m.Groups["name"].Value,
ID = m.Groups["id"].Value,
Date = m.Groups["date"].Value,
Job = m.Groups["job"].Value
}).ToList();
}
The CSV format seems to be what you're looking for (since you want to add some header to this file the actual CSV stars on 6th line):
random text 12234
another random text
User infos:
UserName;ID;Date;Job
John;221223;23.02.2018;job1
Andrew;378292;12.08.2017;job2
Chris;930712;05.11.2016;job3
And then you could read this file and parse it:
var lines = File.ReadAllLines("pathToFile");
var dataStartIndex = lines.IndexOf("UserName;ID;Date;Job");
var Users = lines.Skip(dataStartIndex + 1).Select(s =>
{
var splittedStr = s.Split(';');
return new User(splittedStr[0], splittedStr[1], splittedStr[2], splittedStr[3]);
}).ToList();
If you're working with console entry just skip the header part and let user enter comma separated values for each user on a different string. Parse it in a same way:
var splittedStr = ReadLine().Split(';');
var userToAdd = new User(splittedStr[0], splittedStr[1], splittedStr[2] , splittedStr[3]);
Users.Add(userToAdd);

searching of string according to start with each word in c#

I want to search a keyword by start with any word of any column.
For example displayedCustomers object contain Name which is Sameer Singh.
So when my search variable
searchOption="eer" //it should not search,
searchOption="ingh" //it should not search,
searchOption="Sa" //it should search,
searchOption="Si" //it should search,
searchOption="ameer" //it should not search
I am using this code previously for whole word.But don't know to split space of string and compare with starting element. Please help to do this in efficient way
// Split the word by space
var split = str.Split(" ");
// Check if firstname or lastname starts with searchString
var found = split[0].StartsWith(searchString) || split[1].StartsWith(searchString);
If you dont know if the person has a middle name as well, and you wish to test on that as well:
var searchString = "Sam";
var split = customerName.Split(" ");
var found = false;
foreach(var str in split)
{
found == found || str.StartsWith(searchString);
if(found)
break;
}
Wrapping this up in a method:
public bool NameStartsWith(string name,string searchStr)
{
var split = name.Split(" ");
foreach(var str in split)
{
if(str.StartsWith(searchString))
return true;
}
return false;
}
Use it like this:
var matches = NameStartsWith("Sameer Singh","Sa"); // true
var matches = NameStartsWith("Sameer Singh","Si"); // true
var matches = NameStartsWith("Sameer Singh","S"); // true
var matches = NameStartsWith("Bobby Singer Bobberson","Sing"); // true
var matches = NameStartsWith("Sameer Singh","meer"); // false
You can use String.StartsWith
string name = "Sameer Singh";
string searchOption = "eer";
bool nameStartsWith = name.StartsWith(searchOption);
Console.Write("{0} {1} {2}"
, name
, nameStartsWith ? "starts with" : "starts not with"
, searchOption);
Demo: http://ideone.com/mEh5Q1
You can do that for every word or every column in your record.
For example(assuming DataRow):
bool rowContains = row.ItemArray.Any(o => string.Format("{0}", o).StartsWith(searchOption));
assuming String[]:
bool arrContains = array.Any(str => str.StartsWith(searchOption));
assuming String:
bool nameContains = name.Split().Any(w => w.StartsWith(searchOption));
You should use String.StartsWith together with String.Split:
public bool IsMatching(string Name, string SearchOption)
{
foreach (string s in Name.Split(' '))
{
if s.StartsWith(SearchOption)
return true;
}
return false;
}
// use it like:
if IsMatching("Sameer Singh", "Sa")
{
// ...

Searching the first few characters of every word within a string in C#

I am new to programming languages. I have a requirement where I have to return a record based on a search string.
For example, take the following three records and a search string of "Cal":
University of California
Pascal Institute
California University
I've tried String.Contains, but all three are returned. If I use String.StartsWith, I get only record #3. My requirement is to return #1 and #3 in the result.
Thank you for your help.
If you're using .NET 3.5 or higher, I'd recommend using the LINQ extension methods. Check out String.Split and Enumerable.Any. Something like:
string myString = "University of California";
bool included = myString.Split(' ').Any(w => w.StartsWith("Cal"));
Split divides myString at the space characters and returns an array of strings. Any works on the array, returning true if any of the strings starts with "Cal".
If you don't want to or can't use Any, then you'll have to manually loop through the words.
string myString = "University of California";
bool included = false;
foreach (string word in myString.Split(' '))
{
if (word.StartsWith("Cal"))
{
included = true;
break;
}
}
I like this for simplicity:
if(str.StartsWith("Cal") || str.Contains(" Cal")){
//do something
}
You can try:
foreach(var str in stringInQuestion.Split(' '))
{
if(str.StartsWith("Cal"))
{
//do something
}
}
You can use Regular expressions to find the matches. Here is an example
//array of strings to check
String[] strs = {"University of California", "Pascal Institute", "California University"};
//create the regular expression to look for
Regex regex = new Regex(#"Cal\w*");
//create a list to hold the matches
List<String> myMatches = new List<String>();
//loop through the strings
foreach (String s in strs)
{ //check for a match
if (regex.Match(s).Success)
{ //add to the list
myMatches.Add(s);
}
}
//loop through the list and present the matches one at a time in a message box
foreach (String matchItem in myMatches)
{
MessageBox.Show(matchItem + " was a match");
}
string univOfCal = "University of California";
string pascalInst = "Pascal Institute";
string calUniv = "California University";
string[] arrayofStrings = new string[]
{
univOfCal, pascalInst, calUniv
};
string wordToMatch = "Cal";
foreach (string i in arrayofStrings)
{
if (i.Contains(wordToMatch)){
Console.Write(i + "\n");
}
}
Console.ReadLine();
}
var strings = new List<string> { "University of California", "Pascal Institute", "California University" };
var matches = strings.Where(s => s.Split(' ').Any(x => x.StartsWith("Cal")));
foreach (var match in matches)
{
Console.WriteLine(match);
}
Output:
University of California
California University
This is actually a good use case for regular expressions.
string[] words =
{
"University of California",
"Pascal Institute",
"California University"
}
var expr = #"\bcal";
var opts = RegexOptions.IgnoreCase;
var matches = words.Where(x =>
Regex.IsMatch(x, expr, opts)).ToArray();
The "\b" matches any word boundary (punctuation, space, etc...).

Categories

Resources