Get certain value in the string from text file - c#

I have this in my text file:
000000000:Carrots:$1.99:214:03/11/2015:03/11/2016:$0.99
000000001:Bananas:$1.99:872:03/11/2015:03/11/2016:$0.99
000000002:Chocolate:$2.99:083:03/11/2015:03/11/2016:$1.99
000000003:Spaghetti:$3.99:376:03/11/2015:03/11/2016:$2.99
000000004:Tomato Sauce:$1.99:437:03/11/2015:03/11/2016:$0.99
000000005:Lettuce:$0.99:279:03/11/2015:03/11/2016:$0.99
000000006:Orange Juice:$2.99:398:03/11/2015:03/11/2016:$1.99
000000007:Potatoes:$2.99:792:03/11/2015:03/11/2016:$1.99
000000008:Celery:$0.99:973:03/11/2015:03/11/2016:$0.99
000000009:Onions:$1.99:763:03/11/2015:03/11/2016:$0.99
000000010:Chicken:$8.99:345:03/11/2015:03/11/2016:$7.99
000000010:Chicken:$8.99:345:03/11/2015:03/11/2016:$7.99
I need to get the value of each of the "quantity" values from the position in bold.
EDIT:
I want to also compare the values that I got and give an error if the quantity is low.

Solution with minimal memory consumption in case of large input data.
In additional: there are not processing of incorrect data in quantity column. To do this just replace int.Parse block;
This is several methods to process file data using LINQ expressions
internal static class MyExtensions
{
/// <exception cref="OutOfMemoryException">There is insufficient memory to allocate a buffer for the returned string. </exception>
/// <exception cref="IOException">An I/O error occurs. </exception>
/// <exception cref="ArgumentException"><paramref name="stream" /> does not support reading. </exception>
/// <exception cref="ArgumentNullException"><paramref name="stream" /> is null. </exception>
public static IEnumerable<string> EnumerateLines(this Stream stream)
{
using (var reader = new StreamReader(stream))
{
do
{
var line = reader.ReadLine();
if (line == null) break;
yield return line;
} while (true);
}
}
/// <exception cref="ArgumentNullException"><paramref name="line"/> is <see langword="null" />.</exception>
public static IEnumerable<string> ChunkLine(this string line)
{
if (line == null) throw new ArgumentNullException("line");
return line.Split(':');
}
/// <exception cref="ArgumentNullException"><paramref name="chuckedData"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">Index should be not negative value</exception>
public static string GetColumnData(this IEnumerable<string> chuckedData, int columnIndex)
{
if (chuckedData == null) throw new ArgumentNullException("chuckedData");
if (columnIndex < 0) throw new ArgumentException("Column index should be >= 0", "columnIndex");
return chuckedData.Skip(columnIndex).FirstOrDefault();
}
}
This is example of usage:
private void button1_Click(object sender, EventArgs e)
{
var values = EnumerateQuantityValues("largefile.txt");
// do whatever you need
}
private IEnumerable<int> EnumerateQuantityValues(string fileName)
{
const int columnIndex = 3;
using (var stream = File.OpenRead(fileName))
{
IEnumerable<int> enumerable = stream
.EnumerateLines()
.Select(x => x.ChunkLine().GetColumnData(columnIndex))
.Select(int.Parse);
foreach (var value in enumerable)
{
yield return value;
}
}
}

just consider if you are managed to get all these lines in string array or list.
you can apply the below code to get the collection of quantity as IEnumerable<string>.
var quantity = arr.Select(c =>
{
var temp = c.Split('$');
if (temp.Length > 1)
{
temp = temp[1].Split(':');
if (temp.Length > 1)
{
return temp[1];
}
}
return null;
}).Where(c => c != null);
UPDATE
Check the Fiddle.
https://dotnetfiddle.net/HqKdeI

you simply need to split the string
string data = #"000000000:Carrots:$1.99:214:03/11/2015:03/11/2016:$0.99
000000001:Bananas:$1.99:872:03/11/2015:03/11/2016:$0.99
000000002:Chocolate:$2.99:083:03/11/2015:03/11/2016:$1.99
000000003:Spaghetti:$3.99:376:03/11/2015:03/11/2016:$2.99
000000004:Tomato Sauce:$1.99:437:03/11/2015:03/11/2016:$0.99
000000005:Lettuce:$0.99:279:03/11/2015:03/11/2016:$0.99
000000006:Orange Juice:$2.99:398:03/11/2015:03/11/2016:$1.99
000000007:Potatoes:$2.99:792:03/11/2015:03/11/2016:$1.99
000000008:Celery:$0.99:973:03/11/2015:03/11/2016:$0.99
000000009:Onions:$1.99:763:03/11/2015:03/11/2016:$0.99
000000010:Chicken:$8.99:345:03/11/2015:03/11/2016:$7.99";
string[] rows = data.split(Environment.Newline.ToCharArray());
foreach(var row in rows)
{
string[] cols = row.Split(':');
var quantity = cols[3];
}

You can use String.Split to do this.
// Read all lines into an array
string[] lines = File.ReadAllLines(#"C:\path\to\your\file.txt");
// Loop through each one
foreach (string line in lines)
{
// Split into an array based on the : symbol
string[] split = line.Split(':');
// Get the column based on index
Console.WriteLine(split[3]);
}

Check out the example code below. The string you care about is named theValueYouWantInTheString.
char[] delimiterChar = { ':' };
string input = #"000000010:Chicken:$8.99:345:03/11/2015:03/11/2016:$7.99";
string[] values = input.Split(delimiterChar);
string theValueYouWantInTheString = values[3];

If you have a problem, use regular expression. Now you have two problems.
Here is a program that uses your input as a txt file. The function GetQuantity returns a list with int that contains the quantity. With this approach you can define more groups to extract information from each line.
namespace RegExptester
{
class Program
{
private static List<int> GetQuantity(string txtFile)
{
string tempLineValue;
Regex regex = new Regex(#"[0-9]*:[a-zA-Z]*:\$[0-9]*\.[0-9]*:([0-9]*).*", RegexOptions.Compiled);
List<int> retValue = new List<int>();
using (StreamReader inputReader = new StreamReader(txtFile))
{
while (null != (tempLineValue = inputReader.ReadLine()))
{
Match match = regex.Match(tempLineValue);
if (match.Success)
{
if(match.Groups.Count == 2)
{
int numberValue;
if (int.TryParse(match.Groups[1].Value, out numberValue))
retValue.Add(numberValue);
}
}
}
}
return retValue;
}
static void Main(string[] args)
{
var tmp = GetQuantity("c:\\tmp\\junk.txt");
}
}
}

Apparently from each line you want the part between the 3th and the 4th colon. Linq can do that for you:
using (var textReader = new StreamReader(fileName))
{
// read all text and divide into lines:
var allText = textReader.ReadToEnd();
var allLines = textReader.Split(new char[] {'\r','\n'}, StringSplitIoptions.RemoveEmptyEntries);
// split each line based on ':', and take the fourth element
var myValues = allLines.Select(line => line.Split(new char[] {':'})
.Skip(3)
.FirstOrDefault();
}
If you want less readability, of course you can concatenate these statements into one line.

Related

string word separated by characters and insert into int array

I have the following String word = "12345"; I want to split each character and insert this into an int array
like this-
int[] array = { 1, 2, 3, 4, 5};
whats the fastest and easiest way to do this ?
Try using Linq:
String word = "12345";
int[] array = word
.Select(c => c - '0') // fastest conversion
.ToArray();
String word = "12345";
int[] array = word.Select(x => int.Parse(x.ToString())).ToArray();
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
public static class Extensions
{
/// <summary>
/// Creates a int array from a String.
/// </summary>
/// <param name="source">The source.</param>
/// <returns>an Int Array</returns>
public static IObservable<IEnumerable<int>> StringToIntArray(this string source)
{
return Observable.Create<IEnumerable<int>>(sub =>
{
var sourceAsStringArray = source.ToCharArray().Select(x => x.ToString());
var l = new List<int>();
foreach (var s in sourceAsStringArray)
{
int output = -1;
if (int.TryParse(s, out output))
{
l.Add(output);
}
}
sub.OnNext(l);
sub.OnCompleted();
return Disposable.Empty;
});
}
}
private async void Test()
{
var a = await "12345".StringToIntArray();
var b = await "1a234b5".StringToIntArray();
var invalid = await "IAmNotANumber".StringToIntArray();
}

Text file to two string arrays in wpf using streamreader

I'm trying to read a text file to two string arrays. Array1 is to be all the odd lines, array2 all the even lines. I then add all the items of array1 to a combobox and when that is selected, or as it gets typed, outputs array2 to a textbox.
So far, I have tried a few methods from here, but the big issue seems to be creating the arrays. I tried to get help here before, but the answers didn't actually answer my question. They must be arrays, not lists (which I tried and worked well). I am really confused by this whole thing and my attempted code is now rubbish:
private void ReadFile(string filePath, string customerPhone, string customerName)
{
string line = string.Empty;
var fileSR = new StreamReader(filePath);
bool number = true;
while((line = fileSR.ReadLine()) != null)
{
if (number)
{
customerPhone(line);
number = false;
}
else
{
customerName(line);
number = true;
}
}
fileSR.Close();
}
I'm losing confidence in this whole process, but I need to find a way to make it work, then I can learn why it does.
You are almost there, just use the List<string>.
private void ReadFile(string filePath, string customerPhone, string customerName)
{
string line = string.Empty;
using (var fileSR = new StreamReader(filePath))
{
bool number = true;
List<string> customerPhone = new List<string>();
List<string> customerName = new List<string>();
while((line = fileSR.ReadLine()) != null)
{
if (number)
{
customerPhone.Add(line);
number = false;
}
else
{
customerName.Add(line);
number = true;
}
}
fileSR.Close();
}
}
If you are interested only in Arrays, you could simply call customerName.ToArray() to convert it to an array.
Linq Solution
Alternatively you could use Linq and do this.
var bothArrays = File.ReadLines("filepath") // Read All lines
.Select((line,index) => new {line, index+1}) // index each line
.GroupBy(x=> x/2) // Convert into two groups
.SelectMany(x=> x.Select(s=>s.line).ToArray()) // Convert it to array
.ToArray();
You should use collections to return data, say IList<String>:
private static void ReadFile(String filePath,
IList<String> oddLines,
IList<String> evenLines) {
oddLines.Clear();
evenLines.Clear();
int index = 1; //TODO: start with 0 or with 1
foreach (String line in File.ReadLines(filePath)) {
if (index % 2 == 0)
evenLines.Add(line);
else
oddLines.Add(line);
index += 1;
}
}
using
List<String> names = new List<String>();
List<String> phones = new List<String>();
ReadFile(#"C:\MyDate.txt", names, phones);
// If you want array representation
String[] myNames = names.ToArray();
String[] myPhones = phones.ToArray();
// Let's print out names
Console.Write(String.Join(Envrironment.NewLine, names));
Please, notice, that using File.ReadLines usually more convenient than StreamReader which should be wrapped in using:
// foreach (String line in File.ReadLines(filePath)) equals to
using (var fileSR = new StreamReader(filePath)) {
while ((line = fileSR.ReadLine()) != null) {
...
}
}
This worked! I have these class level strings:
string cFileName = "customer.txt";
string[] cName = new string[0];
string[] cPhone = new string[0];
And then this in the Window Loaded event, but could be used in it's own method:
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
//read file on start
int counter = 0;
string line;
StreamReader custSR = new StreamReader(cFileName);
line = custSR.ReadLine();
while (custSR.Peek() != -1)
{
Array.Resize(ref cPhone, cPhone.Length + 1);
cPhone[cPhone.Length - 1] = line;
counter++;
line = custSR.ReadLine();
Array.Resize(ref cName, cName.Length + 1);
cName[cName.Length - 1] = line;
counter++;
line = custSR.ReadLine();
phoneComboBox.Items.Add(cPhone[cPhone.Length - 1]);
}
custSR.Close();
//focus when program starts
phoneComboBox.Focus();
}

Sorting a set of values with special characters

I have a task to sort a set of values in the DataTable. BUt the tricky part is that the values have special characters like '.' or '-' and negative values as well. The following picture is my current output:
the data are separated by ';' in the picture.
I am using the following code to sort the data.
DataTable myDataTable = new DataTable();
myDataTable.Columns.Add("SN", typeof(string));
string myValues = "";
if (!File.Exists("d:\\DUDBC-values.txt")) //DUDBC-values.txt
{
Console.WriteLine("No file found");
Console.ReadKey();
return;
}
StreamReader file = new StreamReader("d:\\DUDBC-values.txt");
string line;
while ((line = file.ReadLine()) != null)
{
myValues += line;
myValues += ";";
}
file.Close();
string[] myValuesArray = myValues.Split(';');
myValuesArray = myValuesArray.Take(myValuesArray.Count() - 1).ToArray();
foreach (string myValue in myValuesArray)
{
DataRow myRow = myDataTable.NewRow();
myRow["SN"] = myValue;
myDataTable.Rows.Add(myRow);
}
string beforeSort = string.Join(";", myDataTable.AsEnumerable().Select(x => x["SN"]));
Console.WriteLine("Before Sorting:");
Console.WriteLine();
Console.WriteLine(beforeSort);
Console.WriteLine();
IEnumerable<DataRow> sortedValues = myDataTable.AsEnumerable()
.OrderBy(x =>
{
string currentStringValue = x["SN"].ToString();
char[] SplitChar = new char[] { '.', '-' };
string[] currentStringValueArray = new string[1];
try
{
float val = float.Parse(currentStringValue);
currentStringValueArray[0] = currentStringValue;
}
catch {
currentStringValueArray = currentStringValue.Split(SplitChar);
}
string currentPart = "";
int currentPartNumeric = 0;
if (currentStringValueArray.Length > 1)
{
for (int i = 0; i < currentStringValueArray.Length; i++)
{
if (int.TryParse(currentStringValueArray[i], out currentPartNumeric))
{
if (i >= 1)
currentPart += ".";
currentPart += currentPartNumeric.ToString();
}
else
{
try
{
if (i >= 1)
currentPart += ".";
currentPart += (((int)(char.ToUpper(char.Parse(currentStringValueArray[i])))) - 64).ToString();
}
catch { }
}
}
return Convert.ToString(currentPart, CultureInfo.InvariantCulture);
}
else
return 0m.ToString();
});
string afterSort = string.Join(";", sortedValues.Select(x => x["SN"]));
Console.WriteLine("After Sorting:");
Console.WriteLine();
Console.WriteLine(afterSort);
//Copy to your existing datatable
myDataTable = sortedValues.CopyToDataTable();
Console.ReadKey();
I was expecting it to be like this:
-1
1.1.a.1
1.2.a.1
1.2.a.2
1.2.a.3
1.3.1
2.1.2
2.1a.1
2.1a.2
2.5
2.6.1
2.7.1
2.7.2
2.7.16
2.25a
2.25b
2.42.1
2.42.2
3.1.1
3.1.2
3.5.2
3.6a.1
3.6a.2
3.6b.2
5.1a.1
5.1a.2
5.1a.3
5.1b.1
5.1b.2
5.1b.6
6.3.1
6.3.2
6.3.3
6.3.4
6.3.5
6.5.1
6.5.2-C11
6.5.3-C12
17.06.01.b.i
17.06.02.b.i
17.06.02.b.vi
18.01.b
18.02.01.b.iii
1000
What am i doing wrong? Help needed please. I had also asked this type of question in this post until users kept putting different types of values.
It looks like you need to sort in what's called "Natural sort order".
There is a Windows API function, StrCmpLogicalW() that you can use to do such a comparison.
You can wrap this in a set of extension methods for sorting List<T> or arrays like so:
public static class NaturalSortExt
{
/// <summary>Sorts a list in "Natural sort order", i.e. "9" sorts before "10".</summary>
/// <typeparam name="T">The type of elements in the list to be sorted.</typeparam>
/// <param name="self">The list to be sorted.</param>
/// <param name="stringSelector">A projection to convert list elements to strings for comparision.</param>
public static void SortNatural<T>(this List<T> self, Func<T, string> stringSelector)
{
self.Sort((lhs, rhs) => StrCmpLogicalW(stringSelector(lhs), stringSelector(rhs)));
}
/// <summary>Sorts a list in "Natural sort order", i.e. "9" sorts before "10".</summary>
/// <param name="self">The list to be sorted.</param>
public static void SortNatural(this List<string> self)
{
self.Sort(StrCmpLogicalW);
}
/// <summary>Sorts an array in "Natural sort order", i.e. "9" sorts before "10".</summary>
/// <param name="self">The array to be sorted.</param>
public static void SortNatural(this string[] self)
{
Array.Sort(self, StrCmpLogicalW);
}
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
static extern int StrCmpLogicalW(string lhs, string rhs);
}
Then you can just sort your array (or List<T>) as demonstrated in the sample code below:
class Program
{
static void Main()
{
string[] test =
{
"3.1.2",
"1.2.a.1",
"1.2.a.2",
"1.3.1",
"2.1.2",
"2.1a.2",
"2.1a.1",
"-1",
"2.5",
"2.7.1",
"1.1.a.1",
"2.7.16",
"2.7.2",
"2.25a",
"2.6.1",
"5.1a.3",
"2.42.2",
"2.25b",
"2.42.1",
"3.6a.2",
"5.1b.1",
"3.1.1",
"3.5.2",
"3.6a.1",
"3.6b.2",
"5.1a.1",
"1.2.a.3",
"5.1b.2",
"5.1b.6",
"6.3.1",
"6.3.2",
"17.06.02.b.i",
"6.3.3",
"5.1a.2",
"6.3.4",
"6.3.5",
"6.5.1",
"1000",
"6.5.2-C11",
"6.5.3-C12",
"17.06.01.b.i",
"17.06.02.b.vi",
"18.01.b",
"18.02.01.b.iii"
};
string[] expected =
{
"-1",
"1.1.a.1",
"1.2.a.1",
"1.2.a.2",
"1.2.a.3",
"1.3.1",
"2.1.2",
"2.1a.1",
"2.1a.2",
"2.5",
"2.6.1",
"2.7.1",
"2.7.2",
"2.7.16",
"2.25a",
"2.25b",
"2.42.1",
"2.42.2",
"3.1.1",
"3.1.2",
"3.5.2",
"3.6a.1",
"3.6a.2",
"3.6b.2",
"5.1a.1",
"5.1a.2",
"5.1a.3",
"5.1b.1",
"5.1b.2",
"5.1b.6",
"6.3.1",
"6.3.2",
"6.3.3",
"6.3.4",
"6.3.5",
"6.5.1",
"6.5.2-C11",
"6.5.3-C12",
"17.06.01.b.i",
"17.06.02.b.i",
"17.06.02.b.vi",
"18.01.b",
"18.02.01.b.iii",
"1000"
};
test.SortNatural();
Debug.Assert(test.SequenceEqual(expected));
Console.WriteLine(string.Join("\n", test));
}
}

CSV-file values to List<List>

I have a CSV file that I want some values from. One problem is that I don't know how many columns the file has. The number can be different every time I get a new CSV file. It will always have columns and rows with values. I will get it from a normal excel-file.
I want the method to return a List<List>.
ListA(FirstName, LastName, PhoneNumber... and so on) here I don't know how many items ListA will have. It can be different every time.
Inside ListA I want lists of persons like this:
ListA[FirstName] = List1(Zlatan, Lionel, Anders.....)
ListA[LastName] = List2(Ibrahimovic, Messi, Svensson.....) .. and so on.
You could create a class Person
class person {
private string FirstName;
private string LastName;
// others
}
Open the File and split each row in the file with the String.Split()-Method then convert each value and create Objects, which you can add to a List.
List<Person> persons = new List<Person>();
persons.Add(personFromFile);
Thats a pretty short solution but it works
Edit: Variable Fields per Row
If thats the case you could use a List<string[]> stringArraylist; and then add the results of the String.Split()-Method to it.
List<string[]> stringArraylist;
stringArraylist = new List<string[]>();
stringArraylist.Add("Andrew;Pearson;...;lololo;".Split(';'));
Is that more of what you wanted?
There are a lot of questions on SO that deal with parsing CSV files. See here for one: Reading CSV files in C#. I am fairly certain there are some solutions built in to .NET, though I can't recall what they are at the moment. (#ZoharPeled suggested TextFieldParser)
Most of the parsing solutions with give you a collection of rows where each item is a collection of columns. So assuming you have something like a IEnumerable<IList<string>>, you could create a class and use LINQ queries to get what you need:
public class CSVColumns
{
public IEnumerable<IList<string>> CSVContents { get; private set; }
public CSVColumns(IEnumerable<IList<string>> csvcontents)
{
this.CSVContents = csvcontents;
}
public List<string> FirstNames
{
get { return GetColumn("FirstName"); }
}
public List<string> LastNames
{
get { return GetColumn("LastName"); }
}
/// <summary>
/// Gets a collection of the column data based on the name of the column
/// from the header row.
/// </summary>
public List<string> GetColumn(string columnname)
{
//Get the index of the column with the name
var firstrow = CSVContents.ElementAtOrDefault(0);
if (firstrow != null)
{
int index = -1;
foreach (string s in firstrow)
{
index++;
if (s == columnname)
{
return GetColumn(index, true);
}
}
}
return new List<string>();
}
/// <summary>
/// Gets all items from a specific column number but skips the
/// header row if needed.
/// </summary>
public List<string> GetColumn(int index, bool hasHeaderRow = true)
{
IEnumerable<IList<string>> columns = CSVContents;
if (hasHeaderRow)
columns = CSVContents.Skip(1);
return columns.Select(list =>
{
try
{
return list[index];
}
catch (IndexOutOfRangeException ex)
{
return "";
}
}
).ToList();
}
}
I finally got a solution and it's working for me. My friend made it so all creed to him. No user here on stackoverflow so I post it instead.
private List<Attributes> LoadCsv()
{
string filename = #"C:\Desktop\demo.csv";
// Get the file's text.
string whole_file = System.IO.File.ReadAllText(filename);
// Split into lines.
whole_file = whole_file.Replace('\n', '\r');
string[] lines = whole_file.Split(new char[] { '\r' },
StringSplitOptions.RemoveEmptyEntries);
// See how many rows and columns there are.
int num_rows = lines.Length;
int num_cols = lines[0].Split(';').Length;
// Allocate the data array.
string[,] values = new string[num_rows, num_cols];
// Load the array.
for (int r = 0; r < num_rows; r++)
{
string[] line_r = lines[r].Split(';');
for (int c = 0; c < num_cols; c++)
{
values[r, c] = line_r[c];
}
}
var attr = new List<Attributes>();
for (var r = 0; r < num_rows; r++)
{
if (r == 0)
{
for (var c = 0; c < num_cols; c++)
{
attr.Add(new Attributes());
attr[c].Name = values[r, c];
attr[c].Value = new List<String>();
}
}
else
{
for (var b = 0; b < num_cols; b++)
{
var input = values[r, b];
attr[b].Value.Add(input);
}
}
}
// Return the values.
return attr;
}

Regex camelcase in c#

I'm trying to use regex to convert a string like this "North Korea"
to a string like "northKorea" - does someone know how I might accomplish this in c# ?
Cheers
if you know all your input strings are in title case (like "North Korea") you can simply do:
string input = "North Korea";
input = input.Replace(" ",""); //remove spaces
string output = char.ToLower(input[0]) +
input.Substring(1); //make first char lowercase
// output = "northKorea"
if some of your input is not in title case you can use TextInfo.ToTitleCase
string input = "NoRtH kORea";
input = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(input);
input = input.Replace(" ",""); //remove spaces
string output = char.ToLower(input[0]) +
input.Substring(1); //make first char lowercase
// output = "northKorea"
Forget regex.
All you need is a camelCase conversion algorithm:
See here:
http://www.codekeep.net/snippets/096fea45-b426-40fd-8beb-dec49d8a8662.aspx
Use this one:
string camelCase = ConvertCaseString(a, Case.CamelCase);
Copy-pasted in case it goes offline:
void Main() {
string a = "background color-red.brown";
string camelCase = ConvertCaseString(a, Case.CamelCase);
string pascalCase = ConvertCaseString(a, Case.PascalCase);
}
/// <summary>
/// Converts the phrase to specified convention.
/// </summary>
/// <param name="phrase"></param>
/// <param name="cases">The cases.</param>
/// <returns>string</returns>
static string ConvertCaseString(string phrase, Case cases)
{
string[] splittedPhrase = phrase.Split(' ', '-', '.');
var sb = new StringBuilder();
if (cases == Case.CamelCase)
{
sb.Append(splittedPhrase[0].ToLower());
splittedPhrase[0] = string.Empty;
}
else if (cases == Case.PascalCase)
sb = new StringBuilder();
foreach (String s in splittedPhrase)
{
char[] splittedPhraseChars = s.ToCharArray();
if (splittedPhraseChars.Length > 0)
{
splittedPhraseChars[0] = ((new String(splittedPhraseChars[0], 1)).ToUpper().ToCharArray())[0];
}
sb.Append(new String(splittedPhraseChars));
}
return sb.ToString();
}
enum Case
{
PascalCase,
CamelCase
}
You could just split it and put it back together:
string[] split = ("North Korea").Split(' ');
StringBuilder sb = new StringBuilder();
for (int i = 0; i < split.Count(); i++)
{
if (i == 0)
sb.Append(split[i].ToLower());
else
sb.Append(split[i]);
}
Edit: Switched to a StringBuilder instead, like Bazzz suggested.
This builds on Paolo Falabella's answer as a String extension and handles a few boundary cases such as empty string. Since there is some confusion between CamelCase and camelCase, I called it LowerCamelCase as described on Wikipedia. I resisted the temptation to go with nerdCaps.
internal static string ToLowerCamelCase( this string input )
{
string output = "";
if( String.IsNullOrEmpty( input ) == false )
{
output = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase( input ); //in case not Title Case
output = output.Replace( " ", "" ); //remove any white spaces between words
if( String.IsNullOrEmpty( output ) == false ) //handles the case where input is " "
{
output = char.ToLower( output[0] ) + output.Substring( 1 ); //lowercase first (even if 1 character string)
}
}
return output;
}
Use:
string test = "Foo Bar";
test = test.ToLowerCamelCase();
... //test is now "fooBar"
Update:
toong raised a good point in the comments - this will not work for graphemes. See the link provided by toong. There are also examples of iterating graphemes here and here if you want to tweak the above code for graphemes.
String::Split definitely is one of my pet peeves. Also, none of the other answers deal with:
Cultures
All forms of word seperators
Numbers
What happens when it starts with word seperators
I tried to get it as close as possible to what you would find in base class library code:
static string ToCamelCaseInvariant(string value) { return ToCamelCase(value, true, CultureInfo.InvariantCulture); }
static string ToCamelCaseInvariant(string value, bool changeWordCaps) { return ToCamelCase(value, changeWordCaps, CultureInfo.InvariantCulture); }
static string ToCamelCase(string value) { return ToCamelCase(value, true, CultureInfo.CurrentCulture); }
static string ToCamelCase(string value, bool changeWordCaps) { return ToCamelCase(value, changeWordCaps, CultureInfo.CurrentCulture); }
/// <summary>
/// Converts the given string value into camelCase.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="changeWordCaps">If set to <c>true</c> letters in a word (apart from the first) will be lowercased.</param>
/// <param name="culture">The culture to use to change the case of the characters.</param>
/// <returns>
/// The camel case value.
/// </returns>
static string ToCamelCase(string value, bool changeWordCaps, CultureInfo culture)
{
if (culture == null)
throw new ArgumentNullException("culture");
if (string.IsNullOrEmpty(value))
return value;
var result = new StringBuilder(value.Length);
var lastWasBreak = true;
for (var i = 0; i < value.Length; i++)
{
var c = value[i];
if (char.IsWhiteSpace(c) || char.IsPunctuation(c) || char.IsSeparator(c))
{
lastWasBreak = true;
}
else if (char.IsNumber(c))
{
result.Append(c);
lastWasBreak = true;
}
else
{
if (result.Length == 0)
{
result.Append(char.ToLower(c, culture));
}
else if (lastWasBreak)
{
result.Append(char.ToUpper(c, culture));
}
else if (changeWordCaps)
{
result.Append(char.ToLower(c, culture));
}
else
{
result.Append(c);
}
lastWasBreak = false;
}
}
return result.ToString();
}
// Tests
' This is a test. 12345hello world' = 'thisIsATest12345HelloWorld'
'--north korea' = 'northKorea'
'!nOrTH koreA' = 'northKorea'
'System.Console.' = 'systemConsole'
Try the following:
var input = "Hi my name is Rony";
var subStrs = input.ToLower().Split(' ');
var output = "";
foreach(var s in subStrs)
{
if(s!=subStrs[0])
output += s.First().ToString().ToUpper() + String.Join("", s.Skip(1));
else
output += s;
}
should get "hiMyNameIsRony" as the output
string toCamelCase(string s)
{
if (s.Length < 2) return s.ToLower();
return Char.ToLowerInvariant(s[0]) + s.Substring(1);
}
similar to Paolo Falabella's code but survives empty strings and 1 char strings.

Categories