Parsing HTML source using a loop - c#

I have a little problem, I am trying to parse a HTML string in my code, but what i want it to do is split the individual numbers up with a space inbetween each number ie:- " ".
I have made this loop to get rid of the tags
char[] array = new char[source.Length];
int arrayIndex = 0;
bool inside = false;
for (int i = 0; i < source.Length; i++)
{
numberfori = i;
char let = source[i];
if (let == '<')
{
inside = true;
continue;
}
if (let == '>')
{
inside = false;
continue;
}
if (!inside)
{
array[arrayIndex] = let;
Console.WriteLine(arrayIndex);
arrayIndex++;
}
}
return new string(array, 1, arrayIndex);
now this returns :-
201549.0717593/2203.5732.6719.4412.86
but i need :-
2015 49.0 7 175 9 3/22 0 3.57 32.67 19.44 12.86
and here is the HTML code string the loop runs through for you to see so you know where i get it from:-
>2015</a></td><td class="text-right">49.0</td><td class="text-right">7</td><td class="text-right">175</td><td class="text-right">9</td><td class="text-right">3/22</td><td class="text-right">0</td><td class="text-right">3.57</td><td class="text-right">32.67</td><td class="text-right">19.44</td><td class="text-right">12.86</td></tr><tr><td><a data
Eventually i want to put each of these numbers into their own variables but i need to split them first which is the first task one step at a time :)
Thank you for your help

Try adding this:
if (let == '>')
{
inside = false;
if (arrayIndex > 0 && array[arrayIndex - 1] != ' ')
{
array[arrayIndex] = ' ';
arrayIndex++;
}
continue;
}

Related

Split long string in multi lines in C#

I'm fetching data from Dynamics CRM and some fields are of type Multiple Line of Text.
I can only read them as a string using en.GetAttributeValue<string>("multiline_field_name").
My problem is that I'm rendering said string in an HTML markup and some words break.
e.g
container div
************************
This is a very long stri
ng. Any help would be ve
ry much appreciated.
************************
My container element can contain just a bit over 100 characters so I thought I'd break the string on every 100th character.
This is my code:
private string SplitOnNewLine(string str)
{
StringBuilder sb = new StringBuilder();
int splitOnIndex = 100;
int cnt = 1;
for(int i = 0; i <str.Length; i++)
{
if(i % splitOnIndex == 0 && i != 0)
{
if(str[i] == ' ')
{
sb.Insert(i, "<br>");
}
else
{
// Go backwards until space is found and append line break
int copied = splitOnIndex * cnt;
if (copied >= str.Length) break;
do
{
copied--;
if(str[copied] == ' ')
{
sb.Insert(copied, "<br>");
break;
}
}while (str[copied] != ' ');
}
cnt++;
}
else
{
sb.Append(str[i]);
}
}
return sb.ToString();
}
It still doesn't work as expected.
I'd expect something like this:
container div
************************
This is a very long
string. Any help would
be very much
appreciated.
************************
P.S. I've also tried using word-break and word-wrap CSS rules to no avail.
How is about split in two strings after every 100 chars, do a reverse find of e.g. ' ' and do this recursive with the second part of the string as you did already.
string output = "";
for(int i = 0; i < input.Length; )
{
string part = input.Substring( i, ( input.Length - i < 100 )? input.Length - i : 100 );
if ( part.Length < 100 )
{
output += "<br>";
output += input.Substring( i ).TrimStart();
break;
}
else
{
int lastSpaceInLine = part.LastIndexOf( ' ' );
if ( i != 0 )
output += "<br>";
output += input.Substring( i, lastSpaceInLine ).TrimStart();
i += lastSpaceInLine;
}
}
Ok, now I had the chance to check the code...
now it does as expected...

How to create a sequence of strings between "start" and "end" strings [duplicate]

I have a question about iterate through the Alphabet.
I would like to have a loop that begins with "a" and ends with "z". After that, the loop begins "aa" and count to "az". after that begins with "ba" up to "bz" and so on...
Anybody know some solution?
Thanks
EDIT: I forgot that I give a char "a" to the function then the function must return b. if u give "bnc" then the function must return "bnd"
First effort, with just a-z then aa-zz
public static IEnumerable<string> GetExcelColumns()
{
for (char c = 'a'; c <= 'z'; c++)
{
yield return c.ToString();
}
char[] chars = new char[2];
for (char high = 'a'; high <= 'z'; high++)
{
chars[0] = high;
for (char low = 'a'; low <= 'z'; low++)
{
chars[1] = low;
yield return new string(chars);
}
}
}
Note that this will stop at 'zz'. Of course, there's some ugly duplication here in terms of the loops. Fortunately, that's easy to fix - and it can be even more flexible, too:
Second attempt: more flexible alphabet
private const string Alphabet = "abcdefghijklmnopqrstuvwxyz";
public static IEnumerable<string> GetExcelColumns()
{
return GetExcelColumns(Alphabet);
}
public static IEnumerable<string> GetExcelColumns(string alphabet)
{
foreach(char c in alphabet)
{
yield return c.ToString();
}
char[] chars = new char[2];
foreach(char high in alphabet)
{
chars[0] = high;
foreach(char low in alphabet)
{
chars[1] = low;
yield return new string(chars);
}
}
}
Now if you want to generate just a, b, c, d, aa, ab, ac, ad, ba, ... you'd call GetExcelColumns("abcd").
Third attempt (revised further) - infinite sequence
public static IEnumerable<string> GetExcelColumns(string alphabet)
{
int length = 0;
char[] chars = null;
int[] indexes = null;
while (true)
{
int position = length-1;
// Try to increment the least significant
// value.
while (position >= 0)
{
indexes[position]++;
if (indexes[position] == alphabet.Length)
{
for (int i=position; i < length; i++)
{
indexes[i] = 0;
chars[i] = alphabet[0];
}
position--;
}
else
{
chars[position] = alphabet[indexes[position]];
break;
}
}
// If we got all the way to the start of the array,
// we need an extra value
if (position == -1)
{
length++;
chars = new char[length];
indexes = new int[length];
for (int i=0; i < length; i++)
{
chars[i] = alphabet[0];
}
}
yield return new string(chars);
}
}
It's possible that it would be cleaner code using recursion, but it wouldn't be as efficient.
Note that if you want to stop at a certain point, you can just use LINQ:
var query = GetExcelColumns().TakeWhile(x => x != "zzz");
"Restarting" the iterator
To restart the iterator from a given point, you could indeed use SkipWhile as suggested by thesoftwarejedi. That's fairly inefficient, of course. If you're able to keep any state between call, you can just keep the iterator (for either solution):
using (IEnumerator<string> iterator = GetExcelColumns())
{
iterator.MoveNext();
string firstAttempt = iterator.Current;
if (someCondition)
{
iterator.MoveNext();
string secondAttempt = iterator.Current;
// etc
}
}
Alternatively, you may well be able to structure your code to use a foreach anyway, just breaking out on the first value you can actually use.
Edit: Made it do exactly as the OP's latest edit wants
This is the simplest solution, and tested:
static void Main(string[] args)
{
Console.WriteLine(GetNextBase26("a"));
Console.WriteLine(GetNextBase26("bnc"));
}
private static string GetNextBase26(string a)
{
return Base26Sequence().SkipWhile(x => x != a).Skip(1).First();
}
private static IEnumerable<string> Base26Sequence()
{
long i = 0L;
while (true)
yield return Base26Encode(i++);
}
private static char[] base26Chars = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
private static string Base26Encode(Int64 value)
{
string returnValue = null;
do
{
returnValue = base26Chars[value % 26] + returnValue;
value /= 26;
} while (value-- != 0);
return returnValue;
}
The following populates a list with the required strings:
List<string> result = new List<string>();
for (char ch = 'a'; ch <= 'z'; ch++){
result.Add (ch.ToString());
}
for (char i = 'a'; i <= 'z'; i++)
{
for (char j = 'a'; j <= 'z'; j++)
{
result.Add (i.ToString() + j.ToString());
}
}
I know there are plenty of answers here, and one's been accepted, but IMO they all make it harder than it needs to be. I think the following is simpler and cleaner:
static string NextColumn(string column){
char[] c = column.ToCharArray();
for(int i = c.Length - 1; i >= 0; i--){
if(char.ToUpper(c[i]++) < 'Z')
break;
c[i] -= (char)26;
if(i == 0)
return "A" + new string(c);
}
return new string(c);
}
Note that this doesn't do any input validation. If you don't trust your callers, you should add an IsNullOrEmpty check at the beginning, and a c[i] >= 'A' && c[i] <= 'Z' || c[i] >= 'a' && c[i] <= 'z' check at the top of the loop. Or just leave it be and let it be GIGO.
You may also find use for these companion functions:
static string GetColumnName(int index){
StringBuilder txt = new StringBuilder();
txt.Append((char)('A' + index % 26));
//txt.Append((char)('A' + --index % 26));
while((index /= 26) > 0)
txt.Insert(0, (char)('A' + --index % 26));
return txt.ToString();
}
static int GetColumnIndex(string name){
int rtn = 0;
foreach(char c in name)
rtn = rtn * 26 + (char.ToUpper(c) - '#');
return rtn - 1;
//return rtn;
}
These two functions are zero-based. That is, "A" = 0, "Z" = 25, "AA" = 26, etc. To make them one-based (like Excel's COM interface), remove the line above the commented line in each function, and uncomment those lines.
As with the NextColumn function, these functions don't validate their inputs. Both with give you garbage if that's what they get.
Here’s what I came up with.
/// <summary>
/// Return an incremented alphabtical string
/// </summary>
/// <param name="letter">The string to be incremented</param>
/// <returns>the incremented string</returns>
public static string NextLetter(string letter)
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (!string.IsNullOrEmpty(letter))
{
char lastLetterInString = letter[letter.Length - 1];
// if the last letter in the string is the last letter of the alphabet
if (alphabet.IndexOf(lastLetterInString) == alphabet.Length - 1)
{
//replace the last letter in the string with the first leter of the alphbat and get the next letter for the rest of the string
return NextLetter(letter.Substring(0, letter.Length - 1)) + alphabet[0];
}
else
{
// replace the last letter in the string with the proceeding letter of the alphabet
return letter.Remove(letter.Length-1).Insert(letter.Length-1, (alphabet[alphabet.IndexOf(letter[letter.Length-1])+1]).ToString() );
}
}
//return the first letter of the alphabet
return alphabet[0].ToString();
}
just curious , why not just
private string alphRecursive(int c) {
var alphabet = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
if (c >= alphabet.Length) {
return alphRecursive(c/alphabet.Length) + alphabet[c%alphabet.Length];
} else {
return "" + alphabet[c%alphabet.Length];
}
}
This is like displaying an int, only using base 26 in stead of base 10. Try the following algorithm to find the nth entry of the array
q = n div 26;
r = n mod 26;
s = '';
while (q > 0 || r > 0) {
s = alphabet[r] + s;
q = q div 26;
r = q mod 26;
}
Of course, if you want the first n entries, this is not the most efficient solution. In this case, try something like daniel's solution.
I gave this a go and came up with this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Alphabetty
{
class Program
{
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
static int cursor = 0;
static int prefixCursor;
static string prefix = string.Empty;
static bool done = false;
static void Main(string[] args)
{
string s = string.Empty;
while (s != "Done")
{
s = GetNextString();
Console.WriteLine(s);
}
Console.ReadKey();
}
static string GetNextString()
{
if (done) return "Done";
char? nextLetter = GetNextLetter(ref cursor);
if (nextLetter == null)
{
char? nextPrefixLetter = GetNextLetter(ref prefixCursor);
if(nextPrefixLetter == null)
{
done = true;
return "Done";
}
prefix = nextPrefixLetter.Value.ToString();
nextLetter = GetNextLetter(ref cursor);
}
return prefix + nextLetter;
}
static char? GetNextLetter(ref int letterCursor)
{
if (letterCursor == alphabet.Length)
{
letterCursor = 0;
return null;
}
char c = alphabet[letterCursor];
letterCursor++;
return c;
}
}
}
Here is something I had cooked up that may be similar. I was experimenting with iteration counts in order to design a numbering schema that was as small as possible, yet gave me enough uniqueness.
I knew that each time a added an Alpha character, it would increase the possibilities 26x but I wasn't sure how many letters, numbers, or the pattern I wanted to use.
That lead me to the code below. Basically you pass it an AlphaNumber string, and every position that has a Letter, would eventually increment to "z\Z" and every position that had a Number, would eventually increment to "9".
So you can call it 1 of two ways..
//This would give you the next Itteration... (H3reIsaStup4dExamplf)
string myNextValue = IncrementAlphaNumericValue("H3reIsaStup4dExample")
//Or Loop it resulting eventually as "Z9zzZzzZzzz9zZzzzzzz"
string myNextValue = "H3reIsaStup4dExample"
while (myNextValue != null)
{
myNextValue = IncrementAlphaNumericValue(myNextValue)
//And of course do something with this like write it out
}
(For me, I was doing something like "1AA000")
public string IncrementAlphaNumericValue(string Value)
{
//We only allow Characters a-b, A-Z, 0-9
if (System.Text.RegularExpressions.Regex.IsMatch(Value, "^[a-zA-Z0-9]+$") == false)
{
throw new Exception("Invalid Character: Must be a-Z or 0-9");
}
//We work with each Character so it's best to convert the string to a char array for incrementing
char[] myCharacterArray = Value.ToCharArray();
//So what we do here is step backwards through the Characters and increment the first one we can.
for (Int32 myCharIndex = myCharacterArray.Length - 1; myCharIndex >= 0; myCharIndex--)
{
//Converts the Character to it's ASCII value
Int32 myCharValue = Convert.ToInt32(myCharacterArray[myCharIndex]);
//We only Increment this Character Position, if it is not already at it's Max value (Z = 90, z = 122, 57 = 9)
if (myCharValue != 57 && myCharValue != 90 && myCharValue != 122)
{
myCharacterArray[myCharIndex]++;
//Now that we have Incremented the Character, we "reset" all the values to the right of it
for (Int32 myResetIndex = myCharIndex + 1; myResetIndex < myCharacterArray.Length; myResetIndex++)
{
myCharValue = Convert.ToInt32(myCharacterArray[myResetIndex]);
if (myCharValue >= 65 && myCharValue <= 90)
{
myCharacterArray[myResetIndex] = 'A';
}
else if (myCharValue >= 97 && myCharValue <= 122)
{
myCharacterArray[myResetIndex] = 'a';
}
else if (myCharValue >= 48 && myCharValue <= 57)
{
myCharacterArray[myResetIndex] = '0';
}
}
//Now we just return an new Value
return new string(myCharacterArray);
}
}
//If we got through the Character Loop and were not able to increment anything, we retun a NULL.
return null;
}
Here's my attempt using recursion:
public static void PrintAlphabet(string alphabet, string prefix)
{
for (int i = 0; i < alphabet.Length; i++) {
Console.WriteLine(prefix + alphabet[i].ToString());
}
if (prefix.Length < alphabet.Length - 1) {
for (int i = 0; i < alphabet.Length; i++) {
PrintAlphabet(alphabet, prefix + alphabet[i]);
}
}
}
Then simply call PrintAlphabet("abcd", "");

How to ignore reading contents of /*comment*/ while reading a file

Below is my code:
string ckeywords = File.ReadAllText("E:\\ckeywords.csv");
string[] clines = File.ReadAllLines("E:\\cprogram\\cpro\\bubblesort.c");
string letters="";
foreach(string line in clines)
{
char[] c = line.ToCharArray();
foreach(char i in c)
{
if (i == '/' || i == '"')
{
break;
}
else
{
letters = letters + i;
}
}
}
letters = Regex.Replace(letters, #"[^a-zA-Z ]+", " ");
List<string> listofc = letters.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
List<string> listofcsv = ckeywords.Split(new char[] { ',', '\t', '\n', ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()).ToList();
List<string> Commonlist = listofcsv.Intersect(listofc).ToList();
With this if condition, I am able to ignore reading contents of single line comment and contents between ("").
I need to ignore reading contents of multi line comments. Which condition should I use?
Suppose my .c file is having this line of comment so with above code I don't know how to start iterating from /* to */ and to ignore the contents in between.
/*printf("Sorted list in ascending order:\n");
for ( c = 0 ; c < n ; c++ )
printf("%d\n", array[c]);*/
I successfully solved my problem now I can ignore reading contents of /* */ in a simpler way without using Regular Expression.
Here is my code:
string[] clines = File.ReadAllLines("E:\\cprogram\\cpro\\bubblesort.c");
List<string> list = new List<string>();
int startIndexofcomm, endIndexofcomm;
for (int i = 0; i < clines.Length ; i++ )
{
if (clines[i].Contains(#"/*"))
{
startIndexofcomm = clines[i].IndexOf(#"/*");
list.Add(clines[i].Substring(0, startIndexofcomm));
while(!(clines[i].Contains(#"*/")))
{
i++;
}
endIndexofcomm = clines[i].IndexOf(#"*/");
list.Add(clines[i].Substring(endIndexofcomm+2));
continue;
}
list.Add(clines[i]);
}
Here is code that naively does the following:
It strips out any multi-line comments starting with /* and ending with */, even if there are newlines between the two.
It strips out any single-line comments starting with // and ending at the end of the line
It does not strip out any comments like the above if they're within a string that starts with " and ends with a ".
LINQPad code:
void Main()
{
var code = File.ReadAllText(#"d:\temp\test.c");
code.Dump("input");
bool inString = false;
bool inSingleLineComment = false;
bool inMultiLineComment = false;
var output = new StringBuilder();
int index = 0;
while (index < code.Length)
{
// First deal with single line comments: // xyz
if (inSingleLineComment)
{
if (code[index] == '\n' || code[index] == '\r')
{
inSingleLineComment = false;
output.Append(code[index]);
index++;
}
else
index++;
continue;
}
// Then multi-line comments: /* ... */
if (inMultiLineComment)
{
if (code[index] == '*' && index + 1 < code.Length && code[index + 1] == '/')
{
inMultiLineComment = false;
index += 2;
}
else
index++;
continue;
}
// Then deal with strings
if (inString)
{
output.Append(code[index]);
if (code[index] == '"')
inString = false;
index++;
continue;
}
// If we get here we're not in a string or in a comment
if (code[index] == '"')
{
// We found the start of a string
output.Append(code[index]);
inString = true;
index++;
}
else if (code[index] == '/' && index + 1 < code.Length && code[index + 1] == '/')
{
// We found the start of a single line comment
inSingleLineComment = true;
index++;
}
else if (code[index] == '/' && index + 1 < code.Length && code[index + 1] == '*')
{
// We found the start of a multi line comment
inMultiLineComment = true;
index++;
}
else
{
// Just another character
output.Append(code[index]);
index++;
}
}
output.ToString().Dump("output");
}
Sample input:
This should be included // This should not
This should also be included /* while this
should not */ but this should again be included.
Any comments in " /* strings */ " should be included as well.
This goes for "// single line comments" as well.
Sample output (note that there are some spaces at the end of some of the lines below that aren't visible):
This should be included
This should also be included but this should again be included.
Any comments in " /* strings */ " should be included as well.
This goes for "// single line comments" as well.

How to decrement the index of a line in an array of strings?

I am making a code that decrements the line index in an array of strings. My array is like this:
1.ExampleFirst\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
2.ExampleSecond\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
and so on. The lengths of the lines are not the same.
I want the text to be like this:
0.ExampleFirst\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
1.ExampleSecond\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
I have made this code:
int s = 0;
while(s < lineCounter.Count())
{
if (int.TryParse(lineCounter[s].Substring(0, 1), out v) == true && lineCounter[s] != "\n")
{
int m = int.Parse(lineCounter[s].Substring(0,1));
lineCounter[s].Remove(0, lineCounter[s].IndexOf(".")).Insert(0, (m - 1).ToString());
Console.WriteLine(lineCounter[s]);
}
else
Console.WriteLine(lineCounter[s]);
s++;
The "if" is executed only when the line contains the number and when the line is not a new line. The else is executed to write the other lines in the array.(I'm using console.writeLine to see the results. I know I have to change that part)
When I execute this code, I get the following exception in the "if" statement:
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
Additional information: Index and length must refer to a location within the string.
To me this means that "if" is executed even when the new line between the last line of the first text block and the first line of the second text block is encountered. I can't explain why. Help please!
Declaring dotIndex with combination of string.Remove() and string.Insert() may do the trick.
string[] lineCounter = new string[]{
"1.ExampleFirst\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n\n",
"2.ExampleSecond\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n\n"
};
for (int i = 0; i < lineCounter.Count(); ++i) {
int dotIndex = lineCounter[i].IndexOf('.');
if (dotIndex < 1) //must be at least in the position of 2 or above
continue;
int lineIndex = 0;
if (int.TryParse(lineCounter[i].Substring(0, dotIndex), out lineIndex)) { //if can be parsed
lineIndex--; //decrement lineIndex
lineCounter[i] = lineIndex.ToString() + lineCounter[i].Remove(0, dotIndex);
}
}
I prefer to use for-loop to make the loop more definite, but you could change that to while/do.
This works fine in my PC. Output:
Edit:
All the results should be in the lineCounter. If you want to see them along the function, you could do:
for (int i = 0; i < lineCounter.Count(); ++i) {
int dotIndex = lineCounter[i].IndexOf('.');
if (dotIndex < 1) { //must be at least in the position of 2 or above
//Print here
continue;
}
int lineIndex = 0;
if (int.TryParse(lineCounter[i].Substring(0, dotIndex), out lineIndex)) { //if can be parsed
lineIndex--; //decrement lineIndex
lineCounter[i] = lineIndex.ToString() + lineCounter[i].Remove(0, dotIndex);
}
//Print here also
}
you probably want this:
string[] lineCounter=new string[]{
"1.ExampleFirst\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n",
"\n",
"2.ExampleSecond\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n",
"\n"
};
int v = 0;
int s = 0;
while (s < lineCounter.Count())
{
if (int.TryParse(lineCounter[s].Substring(0, 1), out v) == true && lineCounter[s] != "\n")
{
int m = int.Parse(lineCounter[s].Substring(0, 1));
Console.WriteLine(lineCounter[s].Remove(0, lineCounter[s].IndexOf(".")).Insert(0, (m - 1).ToString()));
}
else
Console.WriteLine(lineCounter[s]);
s++;
}
I believe you may be having issues with empty lines on the string array.
Maybe something like this works for you.
IEnumerable<string> ShiftIndexes(IEnumerable<string> lines) {
foreach (string line in lines) {
if (!string.IsNullOrEmpty(line) && char.IsDigit(line, 0)) {
int dotPos = line.IndexOf('.');
int index = int.Parse(line.SubString(0, dotPos));
yield return (index - 1).ToString() + line.SubString(dotPos);
}
else
yield return line;
}
}
And then use it like this:
string[] shiftedLines = ShiftIndexes(originalLines).ToArray();

Concatenate neighboring characters of a special character "-"

i am developing an application using c#.net in which i need that if a input entered by user contains the character '-'(hyphen) then i want the immediate neighbors of the hyphen(-) to be concatenated for example if a user enters
A-B-C then i want it to be replaced with ABC
AB-CD then i want it to be replaced like BC
ABC-D-E then i want it to be replaced like CDE
AB-CD-K then i want it to be replaced like BC and DK both separated by keyword and
after getting this i have to prepare my query to database.
i hope i made the problem clear but if need more clarification let me know.
Any help will be appreciated much.
Thanks,
Devjosh
Use:
string[] input = {
"A-B-C",
"AB-CD",
"ABC-D-E",
"AB-CD-K"
};
var regex = new Regex(#"\w(?=-)|(?<=-)\w", RegexOptions.Compiled);
var result = input.Select(s => string.Concat(regex.Matches(s)
.Cast<Match>().Select(m => m.Value)));
foreach (var s in result)
{
Console.WriteLine(s);
}
Output:
ABC
BC
CDE
BCDK
Untested, but this should do the trick, or at the very least lead you in the right direction.
private string Prepare(string input)
{
StringBuilder output = new StringBuilder();
char[] chars = input.ToCharArray();
for (int i = 0; i < chars.Length; i++)
{
if (chars[i] == '-')
{
if (i > 0)
{
output.Append(chars[i - 1]);
}
if (++i < chars.Length)
{
output.Append(chars[i])
}
else
{
break;
}
}
}
return output.ToString();
}
If you want each pair to form a separate object in an array, try the following code:
private string[] Prepare(string input)
{
List<string> output = new List<string>();
char[] chars = input.ToCharArray();
for (int i = 0; i < chars.Length; i++)
{
if (chars[i] == '-')
{
string o = string.Empty;
if (i > 0)
{
o += chars[i - 1];
}
if (++i < chars.Length)
{
o += chars[i]
}
output.Add(o);
}
}
return output.ToArray();
}
Correct me if I am wrong but surely all you need to do is remove the '-'?
like this:
"A-B-C".Replace("-","");
You can even solve this with a one-liner (although a bit ugly):
String.Join(String.Empty, input.Split('-').Select(q => (q.Length == 0 ? String.Empty : (q.Length > 1 ? (q.First() + q.Last()).ToString() : q.First().ToString())))).Substring(((input[0] + input[1]).ToString().Contains('-') ? 0 : 1), input.Length - ((input[0] + input[1]).ToString().Contains('-') ? 0 : 1) - ((input[input.Length - 1] + input[input.Length - 2]).ToString().Contains('-') ? 0 : 1));
first it splits the string to an array on each '-', then it concatenates only the first and the last character of each string (or just the only character if there's only one, and it leaves the empty string if there's nothing there), and then it concatenates the resulting enumerable to a String. Finally we strip the first and the last letter, if they are not in the needed range.
I know, it's ugly, I'm just saying that it's possible..
Probably it's way better to just use a simple
new Regex(#"\w(?=-)|(?<=-)\w", RegexOptions.Compiled)
and then work with that..
EDIT #Kirill Polishchuk was faster.. his solution should work..
EDIT 2
After the Question has been updated, here's a snippet that should do the trick:
string input = "A-B-C";
string s2;
string s3 = "";
string s4 = "";
var splitted = input.Split('-');
foreach(string s in splitted) {
if (s.Length == 0)
s2 = String.Empty;
else
if (s.Length > 1)
s2 = (s.First() + s.Last()).ToString();
else
s2 = s.First().ToString();
s3 += s4 + s2;
s4 = " and ";
}
int beginning;
int end;
if (input.Length > 1)
{
if ((input[0] + input[1]).ToString().Contains('-'))
beginning = 0;
else
beginning = 1;
if ((input[input.Length - 1] + input[input.Length - 2]).ToString().Contains('-'))
end = 0;
else
end = 1;
}
else
{
if ((input[0]).ToString().Contains('-'))
beginning = 0;
else
beginning = 1;
if ((input[input.Length - 1]).ToString().Contains('-'))
end = 0;
else
end = 1;
}
string result = s3.Substring(beginning, s3.Length - beginning - end);
It's not very elegant, but it should work (not tested though..). it works nearly the same as the one-liner above...

Categories