Validating header names for an SQL column list - c#

I am currently trying to make a user friendly input for people to input SQL headers for a CSV that is created using a temporary table, however I am having issues with validating and changing the names to SQL friendly column headers.
An example input would be as follows:
Name, Ag-e, Gender, Birth Place, Rac+e
Please keep in mind that the input could be ANY word, these are simply an example.
My ideal final output would for the SQL column headers
name age gender birth_place race
however I am having issues checking for invalid characters (which I haven't actually got around to yet.) but my primary issue I am currently having is checking for spaces between words that SHOULD have a space and other spaces at the start of words.
My current output is coming out as(please note that the invalid characters are for testing later.):
Name Ag-e Gender Birth Place Rac+e
Please note that there are double spaces between every one apart from Birth Place which has a single space as it should.
The code I am currently using to achieve this (or not achieve as you can clearly see) is:
columnNamesList = new List<string>(columnNames.Split(splitChar));
columnNamesList[0] = columnNamesList[0].Trim();
columnNamesList[columnNamesList.Count - 1] = columnNamesList[columnNamesList.Count - 1].TrimEnd();
List<string> removalList = new List<string>();
foreach (string i in columnNamesList)
{
if (string.IsNullOrEmpty(i))
{
removalList.Add(i);
}
}
if (removalList.Count < 0)
{
foreach (string i in removalList)
{
columnNamesList.Remove(i);
}
}
for (int i = 0; i < columnNamesList.Count; i++)
{
string s = string.Empty;
string str = columnNamesList[i];
if (Regex.IsMatch(str, #"\w\s\w+", RegexOptions.IgnoreCase))
{
foreach (char c in str)
{
if (Char.IsLetterOrDigit(c) || c == ' ' || c == ',')
s += c;
s = s.Replace(' ', '_');
columnNamesList[i] = s;
}
}
}
string[] columnArray = columnNamesList.ToArray<string>();
columnNames = String.Join(" ", columnArray);

I thought you said that the input is like the first string, comma separated.
Does this not work? All you have to do is remove the unwanted characters (against a blacklist)
var input = "Name, Ag-e, Gender, Birth Place, Rac+e";
var splitInput = input.Split(',')
.Select(i =>
i.Trim()
.ToLower()
.Replace(' ','_'));
var output = string.Join(" ", splitInput.ToArray());

Related

C# Detecting a word in user input textbox

Good evening!
I'm trying to achieve some sort of primitive AI. My Hobby Project basically contains two textboxes. One for input and one for output.
So let's say the user feels the urge to tell my AI his Name after a couple hours of flirting. He would type in "I am called 'Jack Black'"
How would I go about storing his name in a variable? (Or storing First Name and Last Name each in one variable)
Is there some sort of placeholder mechanic where I can store the name string after a set of predicted words? (like "I am called")
My guess:
switch (MyMessage)
{
case "Hi":
BotSays("Hello!");
break;
case "I am called " + PLACEHOLDER:
BotSays("Thats a pretty sick name!");
user_firstName = PLACEHOLDER;
break;
default:
BotSays("Sory me no understand");
break;
}
I hope its understandable what my Question is since I probably cant find the right words to get usefull results on Google, Stack Overflow and Co.
Thank you
Hooboy. I'm not sure if you realize just how monumental of a task you've undertaken. My higher-level suggestion would be: Look up 'Eliza' and try writing a port of it in C#. It's a simple Chat-Bot that you could tweak from there if you're interested.
As for your specific question? I think what you're looking for are Regex'es. Take something like this:
string sampleText = "Hello, my name is Inigo Montoya";
Regex namePattern = new Regex(#"Hello, my name is (?<FirstName>\w+) (?<LastName>\w+)$");
Match match = namePattern.Match(sampleText);
string firstName = match.Groups["FirstName"].Value;
string lastName = match.Groups["LastName"].Value;
MessageBox.Show("He said his name was " + firstName + " " + lastName);
... Regexes are a really neat way of parsing strings in a dynamic way. In this case, it'll let you check whether the name matches that Regex - and if it does, it'll fill out the firstName and lastName variables for you.
Here's one way to do this, although I think regular expressions would make it much simpler. I just don't know RegEx very well.
First you could create a list of the "well known prefixes" to someone introducing themselves:
var stringsBeforeIntroduction = new List<string>
{
"I am called ",
"My name is ",
"People call me ",
"You can refer to me as "
};
And a list of known characters that would follow a name:
var charactersAfterName = new char[]
{
' ', ',', '.', '\n', ';', ':'
};
Then, you can search for the index of the first "introduction prefix" you find:
var firstPrefixFound =
stringsBeforeIntroduction.FirstOrDefault(
prefix => MyMessage.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) > -1);
Now, if firstPrefixFound is not null, then we found the prefix. Next we have to grab the name portion, which will be the rest of the string (or until we hit one of our charactersAfterName characters:
if (firstPrefixFound != null)
{
// Calculate the indexes of the start and end of the name
int prefixLength = firstPrefixFound.Length;
int startName = MyMessage.IndexOf(firstPrefixFound,
StringComparison.OrdinalIgnoreCase) + prefixLength;
int endOfName = MyMessage.IndexOfAny(charactersAfterName, startName) - startName;
if (endOfName < 0) endOfName = MyMessage.Length - startName;
// Assign the name that we found
user_firstName = MyMessage.Substring(startName + prefixLength, endOfName);
}
Putting this together in a function might look like the following, which tries to detect a name from an input string. If it finds a name, it returns true and sets the name parameter to the name found, otherwise it returns false and sets the name parameter to the specified defaultValue string:
private static bool TryGetName(string input, string defaultValue, out string name)
{
var stringsBeforeIntroduction = new List<string>
{
"I am called ",
"My name is ",
"People call me ",
"You can call me ",
"You can refer to me as "
};
var charactersAfterName = new char[]
{
' ', ',', '.', '\n', ';', ':'
};
var firstPrefixFound = stringsBeforeIntroduction.FirstOrDefault(prefix =>
input.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) > -1);
if (firstPrefixFound != null)
{
// Calculate the indexes of the start and end of the name
int prefixLength = firstPrefixFound.Length;
int startName = input.IndexOf(firstPrefixFound,
StringComparison.OrdinalIgnoreCase) + prefixLength;
int endOfName = input.IndexOfAny(charactersAfterName, startName) - startName;
if (endOfName < 0) endOfName = input.Length - startName;
// Assign the name that we found
name = input.Substring(startName, endOfName);
}
else
{
name = defaultValue;
return false;
}
return true;
}
And then the usage would look something like:
string name = "stranger";
while (true)
{
Console.Write("Input some text: ");
Console.WriteLine(TryGetName(Console.ReadLine(), name, out name)
? $"I detected your name is: '{name}'"
: $"I did not detect your name that time, {name}.");
Console.WriteLine();
}
And the output looks like:

select alternate alphabet from string of word in asp.net

I want to generate alternate alphabets from generated word string. E.g. Word is SPACEORION then alphabet should be like this SPCO. Because I need to generate client code as per their name. What would be the suitable solution?
ok, from I understand, this might be what you want but the result of SPACEORION would be SAER and not SACO, so I hope I understood you correctly
string name = "SPACEORION ";
var shortName = "";
while (shortName.Length < 4)
{
foreach (char ch in name.ToCharArray())
{
if (name.IndexOf(ch) % 2 == 0)
{
shortName += ch.ToString();
}
}
}

Read specific values out of a text-file and put them in a list

I have a text-file with many lines, each line looks like this:
"string string double double" between each value is a space. I'd like to read out the first string and last double of every line and put these two values in a existing list. That is my code so far, but it doesnt really work.
private void bOpen_Click(object sender, RoutedEventArgs e)
{
bool exists = File.Exists(#"C:\Users\p2\Desktop\Liste.txt");
if (exists == true)
{
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(#"C:\Users\p2\Desktop\Liste.txt"))
{
Vgl comp = new Vgl();
comp.name = Abzahlungsdarlehenrechner.zgName;
comp.gErg = Abzahlungsdarlehenrechner.zgErg;
GlobaleDaten.VglDaten.Add(comp);
int i = 0;
string line = File.ReadLines(#"Liste.txt").Skip(0).Take(1).First();
while ((line = sr.ReadLine()) != null)
{
sb.Append((line));
listBox.Items.Add(line);
GlobaleDaten.VglDaten.Add(comp);
i++;
}
}
}
I have already read this, but it didnt help How do I read specific value[...]
You can try Linq:
var source = File
.ReadLines(#"C:\Users\p2\Desktop\Liste.txt")
.Select(line => line.Split(' '))
.Select(items => new Vgl() {
name = items[0],
gErg = double.Parse(items[3])
});
// If you want to add into existing list
GlobaleDaten.VglDaten.AddRange(source);
// If you want to create a new list
//List<Vgl> list = source.ToList();
how about
List<Vgl> Result = File.ReadLines(#"C:\Users\p2\Desktop\Liste.txt")
.Select(x => new Vgl()
{
name = x.Split(' ').First(),
gErg = decimal.Parse(x.Split(' ').Last(), NumberStyles.AllowCurrencySymbol)
})
.ToList();
I would avoid storing money within doulbe values because this could lead to rounding issues. Use decimal instead. Examples here: Is a double really unsuitable for money?
You can use:
string[] splitBySpace = line.Split(' ');
string first = splitBySpace.ElementAt(0);
decimal last = Convert.ToDecimal(splitBySpace.ElementAt(splitBySpace.Length - 1));
Edit : To Handle Currency symbol:
string[] splitBySpace = line.Split(' ');
string pattern = #"[^0-9\.\,]+";
string first = splitBySpace.ElementAt(0);
string last = (new Regex(pattern)).Split(splitBySpace.ElementAt(splitBySpace.Length - 1))
.FirstOrDefault();
decimal lastDecimal;
bool success = decimal.TryParse(last, out lastDecimal);
I agree with #Dmitry and fubo, if you are looking for alternatives, you could try this.
var source = File
.ReadLines(#"C:\Users\p2\Desktop\Liste.txt")
.Select(line =>
{
var splits = line.Split(' '));
return new Vgl()
{
name = splits[0],
gErg = double.Parse(splits[3])
};
}
use string.split using space as the delimiter on line to the string into an array with each value. Then just access the first and last array element. Of course, if you aren't absolutely certain that each line contains exactly 4 values, you may want to inspect the length of the array to ensure there are at least 4 values.
reference on using split:
https://msdn.microsoft.com/en-us/library/ms228388.aspx
Read the whole file as a string.
Split the string in a foreach loop using \r\n as a row separator. Add each row to a list of strings.
Iterate through that list and split again each record in another loop using space as field separator and put them into another list of strings.
Now you have all the four fields containig one row. Now just use First and Last methods to get the first word and the last number.

Get the different substrings from one main string

I have the following main string which contains link Name and link URL. The name and url is combined with #;. I want to get the string of each link (name and url i.e. My web#?http://www.google.com), see example below
string teststring = "My web#;http://www.google.com My Web2#;http://www.bing.se Handbooks#;http://www.books.se/";
and I want to get three different strings using any string function:
My web#?http://www.google.com
My Web2#?http://www.bing.se
Handbooks#?http://www.books.de
So this looks like you want to split on the space after a #;, instead of splitting at #; itself. C# provides arbitrary length lookbehinds, which makes that quite easy. In fact, you should probably do the replacement of #; with #? first:
string teststring = "My web#;http://www.google.com My Web2#;http://www.bing.se Handbooks#;http://www.books.se/";
teststring = Regex.Replace(teststring, #"#;", "#?");
string[] substrings = Regex.Split(teststring, #"(?<=#\?\S*)\s+");
That's it:
foreach(var s in substrings)
Console.WriteLine(s);
Output:
My web#?http://www.google.com
My Web2#?http://www.bing.se
Handbooks#?http://www.books.se/
If you are worried that your input might already contain other #? that you don't want to split on, you can of course do the splitting first (using #; in the pattern) and then loop over substrings and do the replacement call inside the loop.
If these are constant strings, you can just use String.Substring. This will require you to count letters, which is a nuisance, in order to provide the right parameters, but it will work.
string string1 = teststring.Substring(0, 26).Replace(";","?");
If they aren't, things get complicated. You could almost do a split with " " as the delimiter, except that your site name has a space. Do any of the substrings in your data have constant features, such as domain endings (i.e. first .com, then .de, etc.) or something like that?
If you have any control on the input format, you may want to change it to be easy to parse, for example by using another separator between items, other than space.
If this format can't be changed, why not just implement the split in code? It's not as short as using a RegEx, but it might be actually easier for a reader to understand since the logic is straight forward.
This will almost definitely will be faster and cheaper in terms of memory usage.
An example for code that solves this would be:
static void Main(string[] args)
{
var testString = "My web#;http://www.google.com My Web2#;http://www.bing.se Handbooks#;http://www.books.se/";
foreach(var x in SplitAndFormatUrls(testString))
{
Console.WriteLine(x);
}
}
private static IEnumerable<string> SplitAndFormatUrls(string input)
{
var length = input.Length;
var last = 0;
var seenSeparator = false;
var previousChar = ' ';
for (var index = 0; index < length; index++)
{
var currentChar = input[index];
if ((currentChar == ' ' || index == length - 1) && seenSeparator)
{
var currentUrl = input.Substring(last, index - last);
yield return currentUrl.Replace("#;", "#?");
last = index + 1;
seenSeparator = false;
previousChar = ' ';
continue;
}
if (currentChar == ';' && previousChar == '#')
{
seenSeparator = true;
}
previousChar = currentChar;
}
}

C# Template parsing and matching with text file

Need some ideas how to solve this problem.
I have a template file what describes the line in the text file. For example:
Template
[%f1%]|[%f2%]|[%f3%]"[%f4%]"[%f5%]"[%f6%]
Text file
1234|1234567|123"12345"12"123456
Now i need to read in the fields from the text file. In the template file fields are described with [%some name%]. Allso in the template file there is set what the field separators are, in this example here there are | and ". The lenght of the fields can change through different files but the separators will stay the same. What would be the best way to read in the template and by template read in the text file?
EDIT: Text file has multiple rows, like this:
1234|1234567|123"12345"12"123456"\r\n
1234|field|123"12345"12"asdasd"\r\n
123sd|1234567|123"asdsadf"12"123456"\r\n
45gg|somedata|123"12345"12"somefield"\r\n
EDIT2: Ok, lets make it even harder. Some fields can contain binary data and i know the starting and end position of the binary data field. I should be able to mark those fields in the template and then the parser will know that this field is binary. How to solve this problem?
I would create a regex based on the template and then parse the text file using that:
class Parser
{
private static readonly Regex TemplateRegex =
new Regex(#"\[%(?<field>[^]]+)%\](?<delim>[^[]+)?");
readonly List<string> m_fields = new List<string>();
private readonly Regex m_textRegex;
public Parser(string template)
{
var textRegexString = '^' + TemplateRegex.Replace(template, Evaluator) + '$';
m_textRegex = new Regex(textRegexString);
}
string Evaluator(Match match)
{
// add field name to collection and create regex for the field
var fieldName = match.Groups["field"].Value;
m_fields.Add(fieldName);
string result = "(.*?)";
// add delimiter to the regex, if it exists
// TODO: check, that only last field doesn't have delimiter
var delimGroup = match.Groups["delim"];
if (delimGroup.Success)
{
string delim = delimGroup.Value;
result += Regex.Escape(delim);
}
return result;
}
public IDictionary<string, string> Parse(string text)
{
var match = m_textRegex.Match(text);
var groups = match.Groups;
var result = new Dictionary<string, string>(m_fields.Count);
for (int i = 0; i < m_fields.Count; i++)
result.Add(m_fields[i], groups[i + 1].Value);
return result;
}
}
You can parse the template using regular expressions. An expression like this will match each field definition and separator:
Match m = Regex.Match(template, #"^(\[%(?<name>.+?)%\](?<separator>.)?)+$")
The match will contain two named groups for (name and separator), each of which will contain a number of captures for each time they matched in the input string. In your example, the separator group would have one less capture than the name group.
You can then iterate over the captures, and use the results to extract the fields from the input string and store the values, like this:
if( m.Success )
{
Group name = m.Groups["name"];
Group separator = m.Groups["separator"];
int index = 0;
Dictionary<string, string> fields = new Dictionary<string, string>();
for( int x = 0; x < name.Captures.Count; ++x )
{
int separatorIndex = input.Length;
if( x < separator.Captures.Count )
separatorIndex = input.IndexOf(separator.Captures[x].Value, index);
fields.Add(name.Captures[x].Value, input.Substring(index, separatorIndex - index));
index = separatorIndex + 1;
}
// Do something with results.
}
Obviously in a real program you'd have to account for invalid input and such, which I didn't do here.
I would do this with a few lines of code. Loop through your template row, grabbing all text between "[" as the variable name and everything else as a terminator. Read all the text to the terminal, assign it to the variable name, repeat.
1- Use API for that sscanf(line, format, __arglist) check here
2- Use string split Like:
public IEnumerable<int> GetDataFromLines(string[] lines)
{
//handle the output data
List<int> data = new List<int>();
foreach (string line in lines)
{
string[] seperators = new string[] { "|", "\"" };
string[] results = line.Split(seperators, StringSplitOptions.RemoveEmptyEntries);
foreach (string result in results)
{
data.Add(int.Parse(result));
}
}
return data;
}
Test it with line:
line = "1234|1234567|123\"12345\"12\"123456";
string[] lines = new string[] { line };
GetDataFromLines(lines);
//output list items are:
1234
1234567
123
12345
12
123456

Categories

Resources