Compare strings with a wildcard - c#

I need to compare a couple of strings with eachother.
I have a wildcard character '%' that can substitute any number (the number can be of any size).
string str1 = "STRUCT[1].VARSTRUCT[10].VAR[1]";
string str2 = "STRUCT[%].VARSTRUCT[%].VAR[%]";
string str3 = "STRUCT[%].VARSTRUCT[%].VAR[2]";
CompareStrings(str1, str2); // Should return TRUE;
CompareStrings(str2, str3); // Should return TRUE;
CompareStrings(str1, str3); // SHould return FALSE;

Here is how you can do it for any two strings containing numbers and wildcards that represent numbers:
private static bool CompareStrings(string str1, string str2)
{
var ar1 = Regex.Matches(str1, #"[\d%]+").Cast<Match>().Select(m => m.Value).ToArray();
var ar2 = Regex.Matches(str2, #"[\d%]+").Cast<Match>().Select(m => m.Value).ToArray();
if (ar1.Length != ar2.Length)
return false;
// Check wildcards and numbers
for (int i = 0; i < ar1.Length; i++)
if (ar1[i] != ar2[i] && ar1[i] != "%" && ar2[i] != "%")
return false;
// Remove wildcards and numbers to check the other characters
if (Regex.Replace(str1, #"[\d%]+", String.Empty) != Regex.Replace(str2, #"[\d%]+", String.Empty))
return false;
return true;
}

a pretty quick and roughly written example of how to do something like that.. but it works
class Program
{
static void Main(string[] args)
{
string str1 = "STRUCT[1].VARSTRUCT[10].VAR[1]";
string str2 = "STRUCT[%].VARSTRUCT[%].VAR[%]";
string str3 = "STRUCT[%].VARSTRUCT[%].VAR[2]";
Console.WriteLine("str1 - str2: " + SpecialComparers.AreEqual(str1, str2));
Console.WriteLine("str2 - str3: " + SpecialComparers.AreEqual(str2, str3));
Console.WriteLine("str1 - str3: " + SpecialComparers.AreEqual(str1, str3));
}
}
class SpecialComparers
{
public static bool AreEqual(String in1, String in2)
{
Regex re = new Regex(#"STRUCT\[(\d+|%)\]\.VARSTRUCT\[(\d+|%)\]\.VAR\[(\d+|%)\]");
var values1 = re.Match(in1).Groups;
var values2 = re.Match(in2).Groups;
if (values1.Count != values2.Count) return false;
for (int i = 1; i <= values1.Count; i++ )
{
if (!values1[i].ToString().Equals(values2[i].ToString())
&& !values1[i].ToString().Equals("%")
&& !values2[i].ToString().Equals("%")
)
return false;
}
return true;
}
}

Related

C#- How to check whether given 2 strings with 2 or 3 words has single letter and compare first letter of 2 strings are same and return true or false?

bool isMatch = false;
var string1list = string1.Trim().ToLower().Split(" ").ToList();
var string2list = string2.Trim().ToLower().Split(" ").ToList();
if (string1List.Count == string2List.Count)
{
int tokenCount = string1List.Count;
for (int i = 0; i < tokenCount; i++)
{
if (string1List[i].Length == 1 || string2List[i].Length == 1)
{
try
{
if (string1List[i][0] == string2List[i][0])
{
isMatch = true;
continue;
}
else
{
isMatch = false;
break;
}
}
catch (Exception ex)
{
throw ex;
}
}
}
}
return isMatch;
Example :
string string1 = "John M Marshal";
string string2 = "John M Marshal";
It has to first check whether the 2 strings have any single char word if yes it should go to comparison.
In comparison it should compare first letter of every word in both strings and if it is same it should return true or else false.
Here you go:
string string1 = "John M Marshal";
string string2 = "John M Marshal";
string[] split1 = string1.Split(' ');
string[] split2 = string2.Split(' ');
bool result =
split1.Any(x => x.Length == 1)
&& split2.Any(x => x.Length == 1)
&& split1.Length == split2.Length
&& split1.Zip(split2, (s1, s2) => s1[0] == s2[0]).All(x => x);
That gives me true.

Enclose with double quotes and separated by comma in csv file

I used this code to omit the quote and to split with comma.
I have a content of csv file like this data.
ex:
"1111","05-24-2017","08:30","0","TRAVEL"
"2222","05-25-2017","08:20","0","TRAVEL"
I used this code:
public bool ReadEntrie(int id, ref string name)
{
int count = 0;
CreateConfigFile();
try
{
fs = new FileStream(data_path, FileMode.Open);
sr = new StreamReader(fs);
bool cond = true;
string temp = "";
while (cond == true)
{
if ((temp = sr.ReadLine()) == null)
{
sr.Close();
fs.Close();
cond = false;
if (count == 0)
return false;
}
if (count == id)
{
string[] stringSplit = temp.Trim('\"').Split(new
String[] { "," }, StringSplitOptions.None);
//string[] stringSplit = temp.Split(',');
int _maxIndex = stringSplit.Length;
name = stringSplit[0];
}
count++;
}
sr.Close();
fs.Close();
return true;
}
catch
{
return false;
}
}
If you don't have commas or quotation marks as a part of data e.g.
"12,34","56","a""bc" -> 12,34 56 a"bc
you can put a simple Linq:
string[][] result = File
.ReadLines(#"C"\MyData.csv")
.Select(line => line
.Split(',')
.Select(item => item.Trim('"'))
.ToArray())
.ToArray();
Further improvement is to return an array of a tailored class:
MyClass[] result = File
.ReadLines(#"C"\MyData.csv")
.Select(line => line
.Split(','))
.Select(items => new MyClass() {
Id = items[0].Trim('"'),
Date = DateTime.ParseExact(items[1].Trim('"') + " " + items[2].Trim('"'),
"MM-dd-yyyy hh:mm",
CultureInfo.InvariantCulture),
Code = items[3].Trim('"'),
Text = items[4].Trim('"'),
})
.ToArray();
The problem is not on that function. It is by other function and I used trim
for it.
string[] stringSplit = temp.Split(',');
int _maxIndex = stringSplit.Length;
name = stringSplit[0].Trim('"');
lastname = stringSplit[1].Trim('"');
phone = stringSplit[2].Trim('"');
mail = stringSplit[3].Trim('"');
website = stringSplit[4].Trim('"');
Try this simple function. It will take care of double quote and comma between double quotes.
private string[] GetCommaSeperatedWords(string sep, string line)
{
List<string> list = new List<string>();
StringBuilder word = new StringBuilder();
int doubleQuoteCount = 0;
for (int i = 0; i < line.Length; i++)
{
string chr = line[i].ToString();
if (chr == "\"")
{
if (doubleQuoteCount == 0)
doubleQuoteCount++;
else
doubleQuoteCount--;
continue;
}
if (chr == sep && doubleQuoteCount == 0)
{
list.Add(word.ToString());
word = new StringBuilder();
continue;
}
word.Append(chr);
}
list.Add(word.ToString());
return list.ToArray();
}

Make every other a-z letter Upper / Lower case, ignoring whitespace

Can somebody tell me what I am doing wrong please? can't seem to get the expected output, i.e. ignore whitespace and only upper/lowercase a-z characters regardless of the number of whitespace characters
my code:
var sentence = "dancing sentence";
var charSentence = sentence.ToCharArray();
var rs = "";
for (var i = 0; i < charSentence.Length; i++)
{
if (charSentence[i] != ' ')
{
if (i % 2 == 0 && charSentence[i] != ' ')
{
rs += charSentence[i].ToString().ToUpper();
}
else if (i % 2 == 1 && charSentence[i] != ' ')
{
rs += sentence[i].ToString().ToLower();
}
}
else
{
rs += " ";
}
}
Console.WriteLine(rs);
Expected output: DaNcInG sEnTeNcE
Actual output: DaNcInG SeNtEnCe
I use flag instead of i because (as you mentioned) white space made this algorithm work wrong:
var sentence = "dancing sentence";
var charSentence = sentence.ToCharArray();
var rs = "";
var flag = true;
for (var i = 0; i < charSentence.Length; i++)
{
if (charSentence[i] != ' ')
{
if (flag)
{
rs += charSentence[i].ToString().ToUpper();
}
else
{
rs += sentence[i].ToString().ToLower();
}
flag = !flag;
}
else
{
rs += " ";
}
}
Console.WriteLine(rs);
Try a simple Finite State Automata with just two states (upper == true/false); another suggestion is to use StringBuilder:
private static string ToDancing(string value) {
if (string.IsNullOrEmpty(value))
return value;
bool upper = false;
StringBuilder sb = new StringBuilder(value.Length);
foreach (var c in value)
if (char.IsLetter(c))
sb.Append((upper = !upper) ? char.ToUpper(c) : char.ToLower(c));
else
sb.Append(c);
return sb.ToString();
}
Test
var sentence = "dancing sentence";
Console.Write(ToDancing(sentence));
Outcome
DaNcInG sEnTeNcE
I think you should declare one more variable called isUpper. Now you have two variables, i indicates the index of the character that you are iterating next and isUpper indicates whether a letter should be uppercase.
You increment i as usual, but set isUpper to true at first:
// before the loop
boolean isUpper = true;
Then, rather than checking whether i is divisible by 2, check isUpper:
if (isUpper)
{
rs += charSentence[i].ToString().ToUpper();
}
else
{
rs += sentence[i].ToString().ToLower();
}
Immediately after the above if statement, "flip" isUpper:
isUpper = !isUpper;
Linq version
var sentence = "dancing sentence";
int i = 0;
string result = string.Concat(sentence.Select(x => { i += x == ' ' ? 0 : 1; return i % 2 != 0 ? char.ToUpper(x) : char.ToLower(x); }));
Sidenote:
please replace charSentence[i].ToString().ToUpper() with char.ToUpper(charSentence[i])
Thanks #Dmitry Bychenko. Best Approach. But i thought as per the OP's (might be a fresher...) mindset, what could be the solution. Here i have the code as another solution.
Lengthy code. I myself don't like but still representing
class Program
{
static void Main(string[] args)
{
var sentence = "dancing sentence large also";
string newString = string.Empty;
StringBuilder newStringdata = new StringBuilder();
string[] arr = sentence.Split(' ');
for (int i=0; i< arr.Length;i++)
{
if (i==0)
{
newString = ReturnEvenModifiedString(arr[i]);
newStringdata.Append(newString);
}
else
{
if(char.IsUpper(newString[newString.Length - 1]))
{
newString = ReturnOddModifiedString(arr[i]);
newStringdata.Append(" ");
newStringdata.Append(newString);
}
else
{
newString = ReturnEvenModifiedString(arr[i]);
newStringdata.Append(" ");
newStringdata.Append(newString);
}
}
}
Console.WriteLine(newStringdata.ToString());
Console.Read();
}
//For Even Test
private static string ReturnEvenModifiedString(string initialString)
{
string newString = string.Empty;
var temparr = initialString.ToCharArray();
for (var i = 0; i < temparr.Length; i++)
{
if (temparr[i] != ' ')
{
if (i % 2 == 0 && temparr[i] != ' ')
{
newString += temparr[i].ToString().ToUpper();
}
else
{
newString += temparr[i].ToString().ToLower();
}
}
}
return newString;
}
//For Odd Test
private static string ReturnOddModifiedString(string initialString)
{
string newString = string.Empty;
var temparr = initialString.ToCharArray();
for (var i = 0; i < temparr.Length; i++)
{
if (temparr[i] != ' ')
{
if (i % 2 != 0 && temparr[i] != ' ')
{
newString += temparr[i].ToString().ToUpper();
}
else
{
newString += temparr[i].ToString().ToLower();
}
}
}
return newString;
}
}
OUTPUT

Split string in square brackets from Google translator

I am receiving a data from a Google Language Translator service and need help splitting the data.
void Start()
{
translateText("Hello, This is a test!", "en", "fr");
}
void translateText(string text, string fromLanguage, string toLanguage)
{
string url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl=" + fromLanguage + "&tl=" + toLanguage + "&dt=t&q=" + Uri.EscapeUriString(text);
StartCoroutine(startTranslator(url));
}
IEnumerator startTranslator(string url)
{
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.Send();
Debug.Log("Raw string Received: " + www.downloadHandler.text);
LanguageResult tempResult = decodeResult(www.downloadHandler.text);
Debug.Log("Original Text: " + tempResult.originalText);
Debug.Log("Translated Text: " + tempResult.translatedText);
Debug.Log("LanguageIso: " + tempResult.languageIso);
yield return null;
}
LanguageResult decodeResult(string result)
{
char[] delims = { '[', '\"', ']', ',' };
string[] arr = result.Split(delims, StringSplitOptions.RemoveEmptyEntries);
LanguageResult tempLang = null;
if (arr.Length >= 4)
{
tempLang = new LanguageResult();
tempLang.translatedText = arr[0];
tempLang.originalText = arr[1];
tempLang.unknowValue = arr[2];
tempLang.languageIso = arr[3];
}
return tempLang;
}
public class LanguageResult
{
public string translatedText;
public string originalText;
public string unknowValue;
public string languageIso;
}
then calling it with translateText("Hello, This is a test!", "en", "fr"); from the Start() function which converts the English sentence to French with ISO 639-1 Code.
The received data looks like this:
[[["Bonjour, Ceci est un test!","Hello, This is a test!",,,0]],,"en"]
I want to split it like this:
Bonjour, Ceci est un test!
Hello, This is a test!
0
en
and put them into a string array in order.
I currently use this:
char[] delims = { '[', '\"', ']', ',' };
string[] arr = result.Split(delims, StringSplitOptions.RemoveEmptyEntries);
This works if there is no comma in the received string. If there is a comma, the splitted values are messed up. What's the best way of splitting this?
EDIT:
With Blorgbeard's solution, the final working code is as below. Hopefully, this will help somebody else. This shouldn't be used for commercial purposes but for personal or school project.
void Start()
{
//translateText("Hello, This is \" / \\ a test !", "en", "fr");
//translateText("Hello, This is , \\ \" a test !", "en", "fr");
translateText("Hello, This is a test!", "en", "fr");
}
void translateText(string text, string fromLanguage, string toLanguage)
{
string url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl=" + fromLanguage + "&tl=" + toLanguage + "&dt=t&q=" + Uri.EscapeUriString(text);
StartCoroutine(startTranslator(url));
}
IEnumerator startTranslator(string url)
{
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.Send();
Debug.Log("Raw string Received: " + www.downloadHandler.text);
LanguageResult tempResult = decodeResult(www.downloadHandler.text);
displayResult(tempResult);
yield return null;
}
void displayResult(LanguageResult translationResult)
{
Debug.Log("Original Text: " + translationResult.originalText);
Debug.Log("Translated Text: " + translationResult.translatedText);
Debug.Log("LanguageIso: " + translationResult.languageIso);
}
LanguageResult decodeResult(string result)
{
string[] arr = Decode(result);
LanguageResult tempLang = null;
if (arr.Length >= 4)
{
tempLang = new LanguageResult();
tempLang.translatedText = arr[0];
tempLang.originalText = arr[1];
tempLang.unknowValue = arr[2];
tempLang.languageIso = arr[3];
}
return tempLang;
}
public class LanguageResult
{
public string translatedText;
public string originalText;
public string unknowValue;
public string languageIso;
}
private string[] Decode(string input)
{
List<string> finalResult = new List<string>();
bool inToken = false;
bool inString = false;
bool escaped = false;
var seps = ",[]\"".ToArray();
var current = "";
foreach (var chr in input)
{
if (!inString && chr == '"')
{
current = "";
inString = true;
continue;
}
if (inString && !escaped && chr == '"')
{
finalResult.Add(current);
current = "";
inString = false;
continue;
}
if (inString && !escaped && chr == '\\')
{
escaped = true;
continue;
}
if (inString && (chr != '"' || escaped))
{
escaped = false;
current += chr;
continue;
}
if (inToken && seps.Contains(chr))
{
finalResult.Add(current);
current = "";
inToken = false;
continue;
}
if (!inString && chr == '"')
{
inString = true;
current = "";
continue;
}
if (!inToken && !seps.Contains(chr))
{
inToken = true;
current = "";
}
current += chr;
}
return finalResult.ToArray();
}
You could code up a simple parser yourself. Here's one I threw together (could use some cleaning up, but demonstrates the idea):
private static IEnumerable<string> Parse(string input) {
bool inToken = false;
bool inString = false;
bool escaped = false;
var seps = ",[]\"".ToArray();
var current = "";
foreach (var chr in input) {
if (!inString && chr == '"') {
current = "";
inString = true;
continue;
}
if (inString && !escaped && chr == '"') {
yield return current;
current = "";
inString = false;
continue;
}
if (inString && !escaped && chr == '\\') {
escaped = true;
continue;
}
if (inString && (chr != '"' || escaped)) {
escaped = false;
current += chr;
continue;
}
if (inToken && seps.Contains(chr)) {
yield return current;
current = "";
inToken = false;
continue;
}
if (!inString && chr == '"') {
inString = true;
current = "";
continue;
}
if (!inToken && !seps.Contains(chr)) {
inToken = true;
current = "";
}
current += chr;
}
}
Here's a jsfiddle demo.
Using Regex.Split you could do something like this for example:
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
var input ="[[[\"Bonjour, Ceci est un test!\",\"Hello, This is a test!\",,,0]],,\"en\"]";
var parse = Regex.Split(input, "\\[|\\]|[^a-zA-Z ],|\",\"|\"|\"");
foreach(var item in parse) {
bool result = !String.IsNullOrEmpty(item) && (Char.IsLetter(item[0]) || Char.IsDigit(item[0]));
if (result) {
Console.WriteLine(item);
}
}
}
}
Output:
Bonjour, Ceci est un test!
Hello, This is a test!
0
en
If you want everything that was split you can simply remove the bool check for alphacharacters.
Here is a crazy idea - split by " and then by the rest (but won't work if there is " between the "'s)
var s = #"[[[""Bonjour, Ceci est un test!"",""Hello, This is a test!"",,,0]],,""en""]";
var a = s.Split('"').Select((x, i) => (i & 1) > 0 ? new[] { x } : x.Split("[],".ToArray(),
StringSplitOptions.RemoveEmptyEntries)).SelectMany(x => x).ToArray();
Debug.Print(string.Join("|", a)); // "Bonjour, Ceci est un test!|Hello, This is a test!|0|en"
You can try regex for splitting. I tested with the sample you provided. It results like this.
var str="[[[\"Bonjour, Ceci est un test!\",\"Hello, This is a test!\",,,0]],,\"en\"]";
var splitted=Regex.Split(str,#"\[|\]|\,");
foreach(var split in splitted){
Console.WriteLine(split );
}
"Bonjour Ceci est un test!"
"Hello This is a test!"
0
"en"

Checking for brackets and removing them

I have actually misunderstood the issue originally,
Basically I have checks to see if there is an error, and to check for certain horrible characters that will break it, however this will not work with brackets, i need to basically check if there are ANY brackets within the string before passing it through SQL and if there are, remove them outright from the string.
for example say I have a string that looks like
[I am a magical string with super powers!){
I wish to remove all of these horrible brackets!
if (compiler.Parser.GetErrors().Count == 0)
{
AstNode root = compiler.Parse(phrase.ToLower());
if (compiler.Parser.GetErrors().Count == 0)
{
try
{
fTextSearch = SearchGrammar.ConvertQuery(root, SearchGrammar.TermType.Inflectional);
}
catch
{
fTextSearch = phrase;
}
}
else
{
fTextSearch = phrase;
}
}
else
{
fTextSearch = phrase;
}
string[] errorChars = errorChars = new string[]
{
"'",
"&"
};
StringBuilder sb = new StringBuilder();
string[] splitString = fTextSearch.Split(errorChars, StringSplitOptions.None);
int numNewCharactersAdded = 0;
foreach (string itm in splitString)
{
sb.Append(itm); //append string
if (fTextSearch.Length > (sb.Length - numNewCharactersAdded))
{
sb.Append(fTextSearch[sb.Length - numNewCharactersAdded]); //append splitting character
sb.Append(fTextSearch[sb.Length - numNewCharactersAdded - 1]); //append it again
numNewCharactersAdded++;
}
}
string newString = sb.ToString();
//Union with the full text search
if (!string.IsNullOrEmpty(fTextSearch))
{
sql.AppendLine("UNION");
sql.AppendLine(commonClause);
sql.AppendLine(string.Format("AND CONTAINS(nt.text, '{0}', LANGUAGE 'English')", newString));
}
this is one way to do it. You can make it more sophisticated by having a set of characters passed in and then testing for those characters rather than hard coding for the brackets.
var someString = "[Hello"
if(someString.contains("["))
{
someString.Replace("[","");
}
if (someString.Contains("]"))
{
someString.Replace("]","");
}
If I understand you right, you just want to remove the brackets if they are not matching.
This will accomplish that:
public string MatchPair(string input, string item1, string item2)
{
var ix1 = input.IndexOf(item1);
var ix2 = input.IndexOf(item2);
if ((ix1 != -1) && (ix2 != -1))
{
return input;
}
if (ix1 == -1)
{
return this.CutString(input, ix2, item2);
}
if (ix2 == -1)
{
return this.CutString(input, ix1, item1);
}
return string.Empty;
}
public string CutString(string input, int ix, string item)
{
string left = input.Substring(0, ix);
string right = input.Substring(ix + item.Length);
return left + right;
}
Here is some testdata that I used:
var str1 = "[hello]";
var str2 = "[hello";
var str3 = "hel]lo";
var str4 = "hel[lo";
var res1 = this.MatchPair(str1, "[", "]");
var res2 = this.MatchPair(str2, "[", "]");
var res3 = this.MatchPair(str3, "[", "]");
var res4 = this.MatchPair(str4, "[", "]");

Categories

Resources