Input #2: profile.Address.AddressLine1
Result: profile.address.addressLine1
Input #2: MyName
Result: myName
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string inputText = "profile.Business.AddressLine1"; //profile.business.addressLine1
//string inputText = "MyName"; //myName
string result = null;
if (inputText.Contains('.'))
{
//make first character lowercase
result = inputText.Substring(0, 1).ToLower() + inputText.Substring(1);
//Loop to find period symbol
//make the next character after the period symbol lowercase
}
else
{
//make first character lowercase
result = inputText.Substring(0, 1).ToLower() + inputText.Substring(1);
}
}
}
}
I suggest using regular expressions:
Code:
using System.Linq; // For test only
using System.Text.RegularExpressions;
...
Func<string, string> toCamel = (source) =>
Regex.Replace(source, #"\b\p{Lu}", m => m.Value.ToLower());
string[] tests = new string[] {
#"profile.Business.AddressLine1",
#"MyFunction(Value, SomeId);",
};
string report = string.Join(Environment.NewLine, tests
.Select(test => $"{test,-40} => {toCamel(test)}"));
Console.WriteLine(report);
we Replace every uppercase letter (\p{Lu}) which is preceeded by word boundary (\b) with lowercase one
Outcome:
profile.Business.AddressLine1 => profile.business.addressLine1
MyFunction(Value, SomeId); => myFunction(value, someId);
If you want to convert after . only, just change the pattern into
#"\.\p{Lu}"
You can try below code:
static void Main(string[] args)
{
string inputText = "profile.Business.AddressLine1";
convertToCamelCase(inputText); //profile.business.addressLine1
}
static string convertToCamelCase(string inputText)
{
string result = string.Empty;
if (inputText.Contains('.'))
{
var inputs = inputText.Split('.');
for (int i = 0; i < inputs.Length; i++)
{
inputs[i] = inputs[i].Substring(0, 1).ToLower() + inputs[i].Substring(1);
}
result = string.Join(".", inputs);
}
else
{
result = convertToCamelCase(inputText);
}
return result;
}
Try below:
var input = "profile.Business.AddressLine1";
var result = string.Join(".",
input.Split('.')
.Select(x => string.IsNullOrEmpty(x)
? "" : Char.ToLower(x.First()) + x.Substring(1)));
Steps to solve your issue:
Split your input string using ..
Change your first letter of each word to lower and concatenate rest of the string.
Again join array with .
Try it online
Inputs:
var input = "profile.Business.AddressLine1";
var test = "Test..Test";
Output:
profile.business.addressLine1
test..test
You should use this code:
static string convertToCamelCase(string inputText)
{
string result = string.Empty;
if (string.IsNullOrEmpty(inputText)) return result;
var inputs = inputText.Split('.');
for(int i = 0; i < inputs.Length; i++)
{
if (String.IsNullOrEmpty(inputs[i])) continue;
inputs[i] = inputs[i].Substring(0, 1).ToLower() + inputs[i].Substring(1);
}
result = string.Join(".", inputs);
return result;
}
Related
I have a string that I converted to a TextInfo.ToTitleCase and removed the underscores and joined the string together. Now I need to change the first and only the first character in the string to lower case and for some reason, I can not figure out how to accomplish it.
class Program
{
static void Main(string[] args)
{
string functionName = "zebulans_nightmare";
TextInfo txtInfo = new CultureInfo("en-us", false).TextInfo;
functionName = txtInfo.ToTitleCase(functionName).Replace('_', ' ').Replace(" ", String.Empty);
Console.Out.WriteLine(functionName);
Console.ReadLine();
}
}
Results: ZebulansNightmare
Desired Results: zebulansNightmare
UPDATE:
class Program
{
static void Main(string[] args)
{
string functionName = "zebulans_nightmare";
TextInfo txtInfo = new CultureInfo("en-us", false).TextInfo;
functionName = txtInfo.ToTitleCase(functionName).Replace("_", string.Empty).Replace(" ", string.Empty);
functionName = $"{functionName.First().ToString().ToLowerInvariant()}{functionName.Substring(1)}";
Console.Out.WriteLine(functionName);
Console.ReadLine();
}
}
Produces the desired output.
You just need to lower the first char in the array. See this answer
Char.ToLowerInvariant(name[0]) + name.Substring(1)
As a side note, seeing as you are removing spaces you can replace the underscore with an empty string.
.Replace("_", string.Empty)
If you're using .NET Core 3 or .NET 5, you can call:
System.Text.Json.JsonNamingPolicy.CamelCase.ConvertName(someString)
Then you'll definitely get the same results as ASP.NET's own JSON serializer.
Implemented Bronumski's answer in an extension method (without replacing underscores).
public static class StringExtension
{
public static string ToCamelCase(this string str)
{
if(!string.IsNullOrEmpty(str) && str.Length > 1)
{
return char.ToLowerInvariant(str[0]) + str.Substring(1);
}
return str.ToLowerInvariant();
}
}
//Or
public static class StringExtension
{
public static string ToCamelCase(this string str) =>
string.IsNullOrEmpty(str) || str.Length < 2
? str.ToLowerInvariant()
: char.ToLowerInvariant(str[0]) + str.Substring(1);
}
and to use it:
string input = "ZebulansNightmare";
string output = input.ToCamelCase();
Here is my code, in case it is useful to anyone
// This converts to camel case
// Location_ID => locationId, and testLEFTSide => testLeftSide
static string CamelCase(string s)
{
var x = s.Replace("_", "");
if (x.Length == 0) return "null";
x = Regex.Replace(x, "([A-Z])([A-Z]+)($|[A-Z])",
m => m.Groups[1].Value + m.Groups[2].Value.ToLower() + m.Groups[3].Value);
return char.ToLower(x[0]) + x.Substring(1);
}
If you prefer Pascal-case use:
static string PascalCase(string s)
{
var x = CamelCase(s);
return char.ToUpper(x[0]) + x.Substring(1);
}
The following code works with acronyms as well. If it is the first word it converts the acronym to lower case (e.g., VATReturn to vatReturn), and otherwise leaves it as it is (e.g., ExcludedVAT to excludedVAT).
name = Regex.Replace(name, #"([A-Z])([A-Z]+|[a-z0-9_]+)($|[A-Z]\w*)",
m =>
{
return m.Groups[1].Value.ToLower() + m.Groups[2].Value.ToLower() + m.Groups[3].Value;
});
Example 01
public static string ToCamelCase(this string text)
{
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(text);
}
Example 02
public static string ToCamelCase(this string text)
{
return string.Join(" ", text
.Split()
.Select(i => char.ToUpper(i[0]) + i.Substring(1)));
}
Example 03
public static string ToCamelCase(this string text)
{
char[] a = text.ToLower().ToCharArray();
for (int i = 0; i < a.Count(); i++)
{
a[i] = i == 0 || a[i - 1] == ' ' ? char.ToUpper(a[i]) : a[i];
}
return new string(a);
}
Adapted from Leonardo's answer:
static string PascalCase(string str) {
TextInfo cultInfo = new CultureInfo("en-US", false).TextInfo;
str = Regex.Replace(str, "([A-Z]+)", " $1");
str = cultInfo.ToTitleCase(str);
str = str.Replace(" ", "");
return str;
}
Converts to PascalCase by first adding a space before any group of capitals, and then converting to title case before removing all the spaces.
Here's my code, includes lowering all upper prefixes:
public static class StringExtensions
{
public static string ToCamelCase(this string str)
{
bool hasValue = !string.IsNullOrEmpty(str);
// doesn't have a value or already a camelCased word
if (!hasValue || (hasValue && Char.IsLower(str[0])))
{
return str;
}
string finalStr = "";
int len = str.Length;
int idx = 0;
char nextChar = str[idx];
while (Char.IsUpper(nextChar))
{
finalStr += char.ToLowerInvariant(nextChar);
if (len - 1 == idx)
{
// end of string
break;
}
nextChar = str[++idx];
}
// if not end of string
if (idx != len - 1)
{
finalStr += str.Substring(idx);
}
return finalStr;
}
}
Use it like this:
string camelCasedDob = "DOB".ToCamelCase();
If you are Ok with the Newtonsoft.JSON dependency, the following string extension method will help. The advantage of this approach is the serialization will work on par with standard WebAPI model binding serialization with high accuracy.
public static class StringExtensions
{
private class CamelCasingHelper : CamelCaseNamingStrategy
{
private CamelCasingHelper(){}
private static CamelCasingHelper helper =new CamelCasingHelper();
public static string ToCamelCase(string stringToBeConverted)
{
return helper.ResolvePropertyName(stringToBeConverted);
}
}
public static string ToCamelCase(this string str)
{
return CamelCasingHelper.ToCamelCase(str);
}
}
Here is the working fiddle
https://dotnetfiddle.net/pug8pP
In .Net 6 and above
public static class CamelCaseExtension
{
public static string ToCamelCase(this string str) =>
char.ToLowerInvariant(str[0]) + str[1..];
}
public static string CamelCase(this string str)
{
TextInfo cultInfo = new CultureInfo("en-US", false).TextInfo;
str = cultInfo.ToTitleCase(str);
str = str.Replace(" ", "");
return str;
}
This should work using System.Globalization
var camelCaseFormatter = new JsonSerializerSettings();
camelCaseFormatter.ContractResolver = new CamelCasePropertyNamesContractResolver();
JsonConvert.SerializeObject(object, camelCaseFormatter));
Strings are immutable, but we can use unsafe code to make it mutable though.
The string.Copy insured that the original string stays as is.
In order for these codes to run you have to allow unsafe code in your project.
public static unsafe string ToCamelCase(this string value)
{
if (value == null || value.Length == 0)
{
return value;
}
string result = string.Copy(value);
fixed (char* chr = result)
{
char valueChar = *chr;
*chr = char.ToLowerInvariant(valueChar);
}
return result;
}
This version modifies the original string, instead of returning a modified copy. This will be annoying though and totally uncommon. So make sure the XML comments are warning users about that.
public static unsafe void ToCamelCase(this string value)
{
if (value == null || value.Length == 0)
{
return value;
}
fixed (char* chr = value)
{
char valueChar = *chr;
*chr = char.ToLowerInvariant(valueChar);
}
return value;
}
Why use unsafe code though? Short answer... It's super fast.
Here's my code which is pretty simple. My major objective was to ensure that camel-casing was compatible with what ASP.NET serializes objects to, which the above examples don't guarantee.
public static class StringExtensions
{
public static string ToCamelCase(this string name)
{
var sb = new StringBuilder();
var i = 0;
// While we encounter upper case characters (except for the last), convert to lowercase.
while (i < name.Length - 1 && char.IsUpper(name[i + 1]))
{
sb.Append(char.ToLowerInvariant(name[i]));
i++;
}
// Copy the rest of the characters as is, except if we're still on the first character - which is always lowercase.
while (i < name.Length)
{
sb.Append(i == 0 ? char.ToLowerInvariant(name[i]) : name[i]);
i++;
}
return sb.ToString();
}
}
/// <summary>
/// Gets the camel case from snake case.
/// </summary>
/// <param name="snakeCase">The snake case.</param>
/// <returns></returns>
private string GetCamelCaseFromSnakeCase(string snakeCase)
{
string camelCase = string.Empty;
if(!string.IsNullOrEmpty(snakeCase))
{
string[] words = snakeCase.Split('_');
foreach (var word in words)
{
camelCase = string.Concat(camelCase, Char.ToUpperInvariant(word[0]) + word.Substring(1));
}
// making first character small case
camelCase = Char.ToLowerInvariant(camelCase[0]) + camelCase.Substring(1);
}
return camelCase;
}
I use This method to convert the string with separated by "_" to Camel Case
public static string ToCamelCase(string? s)
{
var nameArr = s?.ToLower().Split("_");
var str = "";
foreach (var name in nameArr.Select((value, i) => new { value, i }))
{
if(name.i >= 1)
{
str += string.Concat(name.value[0].ToString().ToUpper(), name.value.AsSpan(1));
}
else
{
str += name.value ;
}
}
return str;
}
u can change the separated by "_" with any other you want.
Simple and easy in build c#
using System;
using System.Globalization;
public class SamplesTextInfo {
public static void Main() {
// Defines the string with mixed casing.
string myString = "wAr aNd pEaCe";
// Creates a TextInfo based on the "en-US" culture.
TextInfo myTI = new CultureInfo("en-US",false).TextInfo;
// Changes a string to lowercase.
Console.WriteLine( "\"{0}\" to lowercase: {1}", myString, myTI.ToLower( myString ) );
// Changes a string to uppercase.
Console.WriteLine( "\"{0}\" to uppercase: {1}", myString, myTI.ToUpper( myString ) );
// Changes a string to titlecase.
Console.WriteLine( "\"{0}\" to titlecase: {1}", myString, myTI.ToTitleCase( myString ) );
}
}
/*
This code produces the following output.
"wAr aNd pEaCe" to lowercase: war and peace
"wAr aNd pEaCe" to uppercase: WAR AND PEACE
"wAr aNd pEaCe" to titlecase: War And Peace
*/
public static class StringExtension
{
public static string ToCamelCase(this string str)
{
return string.Join(" ", str
.Split()
.Select(i => char.ToUpper(i[0]) + i.Substring(1).ToLower()));
}
}
I had the same issue with titleCase so I just created one, hope this helps this is an extension method.
public static string ToCamelCase(this string text)
{
if (string.IsNullOrEmpty(text))
return text;
var separators = new[] { '_', ' ' };
var arr = text
.Split(separators)
.Where(word => !string.IsNullOrWhiteSpace(word));
var camelCaseArr = arr
.Select((word, i) =>
{
if (i == 0)
return word.ToLower();
var characterArr = word.ToCharArray()
.Select((character, characterIndex) => characterIndex == 0
? character.ToString().ToUpper()
: character.ToString().ToLower());
return string.Join("", characterArr);
});
return string.Join("", camelCaseArr);
}
I have some problems to format strings from a List<string>
Here's a picture of the List values:
Now I managed to manipulate some of the values but others not, here's what I used to manipulate:
string prepareStr(string itemToPrepare) {
string first = string.Empty;
string second = string.Empty;
if (itemToPrepare.Contains("\"")) {
first = itemToPrepare.Replace("\"", "");
}
if (first.Contains("-")) {
int beginIndex = first.IndexOf("-");
second = first.Remove(beginIndex, first.Length - beginIndex);
}
return second;
}
Here's a picture of the Result:
I need to get the clear Path without the (-startup , -minimzed , MSRun , double apostrophes).
What am I doing wrong here?
EDIT my updated code:
void getStartUpEntries() {
var startEntries = StartUp.getStartUp();
if (startEntries != null && startEntries.Count != 0) {
for (int i = 0; i < startEntries.Count; i++) {
var splitEntry = startEntries[i].Split(new string[] { "||" }, StringSplitOptions.None);
var str = splitEntry[1];
var match = Regex.Match(str, #"\|\|""(?<path>(?:\""|[^""])*)""");
var finishedPath = match.Groups["path"].ToString();
if (!string.IsNullOrEmpty(finishedPath)) {
if (File.Exists(finishedPath) || Directory.Exists(finishedPath)) {
var _startUpObj = new StartUp(splitEntry[0], finishedPath,
"Aktiviert: ", new Uri("/Images/inWatch.avOK.png", UriKind.RelativeOrAbsolute),
StartUp.getIcon(finishedPath));
_startUpList.Add(_startUpObj);
}
else {
var _startUpObjNo = new StartUp(splitEntry[0], finishedPath,
"Aktiviert: ", new Uri("/Images/inWatch.avOK.png", UriKind.RelativeOrAbsolute),
StartUp.getIcon(string.Empty));
_startUpList.Add(_startUpObjNo);
}
}
var _startUpObjLast = new StartUp(splitEntry[0], splitEntry[1],
"Aktiviert: ", new Uri("/Images/inWatch.avOK.png", UriKind.RelativeOrAbsolute),
StartUp.getIcon(string.Empty));
_startUpList.Add(_startUpObjLast);
}
lstStartUp.ItemsSource = _startUpList.OrderBy(item => item.Name).ToList();
}
You could use a regex to extract the path:
var str = #"0Raptr||""C:\Program Files (x86)\Raptr\raptrstub.exe"" --startup"
var match = Regex.Match(str, #"\|\|""(?<path>(?:\""|[^""])*)""");
Console.WriteLine(match.Groups["path"]);
This will match any (even empty) text (either an escaped quote, or any character which is not a quote) between two quote characters preceeded by two pipe characters.
Similarly, you could simply split on the double quotes as I see that's a repeating occurrence in your examples and take the second item in the split array:
var path = new Regex("\"").Split(s)[1];
This is and update to your logic without using any Regex:
private string prepareStr(string itemToPrepare)
{
string result = null;
string startString = #"\""";
string endString = #"\""";
int startPoint = itemToPrepare.IndexOf(startString);
if (startPoint >= 0)
{
startPoint = startPoint + startString.Length;
int EndPoint = itemToPrepare.IndexOf(endString, startPoint);
if (EndPoint >= 0)
{
result = itemToPrepare.Substring(startPoint, EndPoint - startPoint);
}
}
return result;
}
Hope you can give me some light on this:
I have this var
string TestString = "KESRNAN FOREST S BV";
I want to replace the S that is alone, so I tried with the following
public static string FixStreetName(string streetName)
{
string result = "";
string stringToCheck = streetName.ToUpper();
// result = stringToCheck.Replace(StreetDirection(stringToCheck), "").Replace(StreetType(stringToCheck),"").Trim();
result = stringToCheck.Replace("S", "").Replace("BV", "").Trim();
return result;
}
But this is replacing all S on that string. any ideas?
Use regular expressions,
\b
denotes word boundaries. here is an example on C# Pad
string x = "KESRNAN FOREST S BV";
var result = System.Text.RegularExpressions.Regex.Replace(x, #"\bS\b", "");
Console.WriteLine(result);
If you can easily identify certain "delimiter" characters, one possibility is to 1. split your input string into several parts using string.Split; then 2. pick the parts that you want, and finally 3. "glue" them back together using string.Join:
var partsToExclude = new string[] { "S", "BV" };
/* 1. */ var parts = stringToCheck.Split(' ');
/* 2. */ var selectedParts = parts.Where(part => !partsToExclude.Contains(part));
/* 3. */ return string.Join(" ", selectedParts.ToArray());
Using Regex:
string input = "S KESRNAN FOREST S BV S";
string result = Regex.Replace(input, #"\b(S)", "");
As you can see alone S is before a space " ". In the other word have this string "S " which want to replace it.
Try this :
string TestString = "KESRNAN FOREST S BV";
string replacement = TestString.Replace("S ", "");
Another way of doing what you want:
using System;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string testString = "S KESRNAN S FOREST BV S";
// deleting S in middle of string
for (int i = 1; i < testString.Length-1; i++)
{
if (testString[i]=='S'&&testString[i-1]==' '&&testString[i+1]==' ')
testString=testString.Remove(i,2);
}
// deleting S in the begining of string
if (testString.StartsWith("S "))
testString = testString.Remove(0, 2);
// deleting S at the end of string
if (testString.EndsWith(" S"))
testString = testString.Remove(testString.Length-2, 2);
Console.WriteLine(testString);
}
}
}
string strExample =
"\"10553210\",\"na\",\"398,633,000\",\"20130709\",\"20130502\",\"20120724\",";
how to split above string with ","
I need an answer like
string[] arrExample = YourFunc(strExample);
arrExample[0] == "10553210";
arrExample[1] == "na";
arrExample[2] == "398,633,000";
...
with split option.
thanks in advance
Here is an easy way,
using Microsoft.VisualBasic.FileIO;
IList<string> arrExample;
using(var csvParser = new TextFieldParser(new StringReader(strExample))
{
fields = csvParser.ReadFields();
}
You may split not by comma "," but by whole string "\",\"".
Do not forget to Trim leading and trailing quotations ":
String strExample =
"\"10553210\",\"na\",\"398,633,000\",\"20130709\",\"20130502\",\"20120724\"";
string[] arrExample = St.Trim('"').Split(new String[] {"\",\""}, StringSplitOptions.None);
You can split on "," , The first and last entry you have to clean the " in the last and first entry:
string[] arr = strExample .Split(new string[] { "\",\"" },
StringSplitOptions.None);
//remove the extra quotes from the last and the first entry
arr[0] = arr[0].SubString(1,arr[0].Length - 1);
int last = arr.Length - 1;
arr[last] = arr[last].SubString(0,arr[last].Length - 1);
string[] arrExample = strExample.Split(",");
would do it, but your code won't compile. I assume you meant:
string strExample = "10553210,na,398,633,000,20130709,20130502,20120724";
If this isn't what you meant, please correct the question.
Assuming you meant this:
string strExample = "\"10553210\",\"na\",\"398,633,000\",\"20130709\",\"20130502\",\"20120724\"";
Split then Select the substring:
string[] parts = strExample.Split(',').Select(x => x.Substring(1, x.Length - 2)).ToArray();
Result:
strExample.Split(',');
You need to escape the double quotes if they're meant to be contained in your example string.
Using the example from Jodrell
private string[] SplitFields(string csvValue)
{
//if there aren't quotes, use the faster function
if (!csvValue.Contains('\"') && !csvValue.Contains('\''))
{
return csvValue.Trim(',').Split(',');
}
else
{
//there are quotes, use this built in text parser
using(var csvParser = new Microsoft.VisualBasic.FileIO.TextFieldParser(new StringReader(csvValue.Trim(','))))
{
csvParser.Delimiters = new string[] { "," };
csvParser.HasFieldsEnclosedInQuotes = true;
return csvParser.ReadFields();
}
}
}
This worked for me
public static IEnumerable<string> SplitCSV(string strInput)
{
string[] str = strInput.Split(',');
if (str == null)
yield return null;
StringBuilder quoteS = null;
foreach (string s in str)
{
if (s.StartsWith("\""))
{
if (s.EndsWith("\""))
{
yield return s;
}
quoteS = new StringBuilder(s);
continue;
}
if (quoteS != null)
{
quoteS.Append($",{s}");
if (s.EndsWith("\""))
{
string s1 = quoteS.ToString();
quoteS = null;
yield return s1;
}
else
continue;
}
yield return s;
}
}
static void Main(string[] args)
{
string s = "111,222,\"33,44,55\",666,\"77,88\",\"99\"";
Console.WriteLine(s);
var sp = SplitCSV(s);
foreach (string s1 in sp)
{
Console.WriteLine(s1);
}
Console.ReadKey();
}
you can do that by doing this ..
string stringname= "10553210,na,398,633,000,20130709,20130502,20120724";
List<String> asd = stringname.Split(',');
or if you wanr array then
array[] asd = stringname.Split(',').ToArray;
I have string separated by dot ('.') characters that represents a hierarchy:
string source = "Class1.StructA.StructB.StructC.FieldA";
How can I use C# and linq to split the string into separate strings to show their hierarchy? Such as:
string[] result = new string[]
{
"Class1",
"Class1.StructA",
"Class1.StructA.StructB",
"Class1.StructA.StructB.FieldA"
};
Split the string by the delimiters taking 1...N of the different levels and rejoin the string.
const char DELIMITER = '.';
var source = "Class1.StructA.StructB.StructC.FieldA";
var hierarchy = source.Split(DELIMITER);
var result = Enumerable.Range(1, hierarchy.Length)
.Select(i => String.Join(".", hierarchy.Take(i)))
.ToArray();
Here's a more efficient way to do this without LINQ:
const char DELIMITER = '.';
var source = "Class1.StructA.StructB.StructC.FieldA";
var result = new List<string>();
for (int i = 0; i < source.Length; i++)
{
if (source[i] == DELIMITER)
{
result.Add(source.Substring(0, i));
}
}
result.Add(source); // assuming there is no trailing delimiter
Here is solution that uses aggregation:
const string separator = ".";
const string source = "Class1.StructA.StructB.StructC.FieldA";
// Get the components.
string[] components = source.Split(new [] { separator }, StringSplitOptions.None);
List<string> results = new List<string>();
// Aggregate with saving temporary results.
string lastResult = components.Aggregate((total, next) =>
{
results.Add(total);
return string.Join(separator, total, next);
});
results.Add(lastResult);
Here's a solution completely without LINQ:
public static string[] GetHierarchy(this string path)
{
var res = path.Split('.');
string last = null;
for (int i = 0; i < res.Length; ++i)
{
last = string.Format("{0}{1}{2}", last, last != null ? "." : null, res[i]);
res[i] = last;
}
return res;
}
Shlemiel the painter approach is better than the "super Shlemiel" string.Join in this case.
const char DELIMITER = '.';
string soFar = "";
List<string> result = source.Split(DELIMITER).Select(s =>
{
if (soFar != "") { soFar += DELIMITER; };
soFar += s;
return soFar;
}).ToList();