I have a string in c#. I want to split that string into 2 words string sets like:
string str = "Split handles splitting upon string and character delimiters."
Output should be:
1: "Split handles"
2: "splitting upon"
3: "string and"
4: "character delimiters."
What should be the best method to do this?
Here is what i have tried yet:
private List<string> Spilt(string text)
{
List<string> bunch = new List<string>();
int block = 15;
string[] words = text.Split(' ');
int length = words.Length;
int remain = 0;
while(remain < length)
{
bunch.Add(string.Join(" ", words.Take(block)));
remain += block;
}
return bunch;
}
The simplest approach would be to split at each space, and then "re-join" the pairs back, like this:
var pairs = str.Split(' ')
.Select((s,i) => new {s, i})
.GroupBy(n => n.i / 2)
.Select(g => string.Join(" ", g.Select(p=>p.s)))
.ToList();
Demo on ideone.
Try this
string str = "Split handles splitting upon string and character delimiters.";
var strnew = str.Split(' ');
var strRes = string.Empty;
int j = 1;
for (int i = 0; i < strnew.Length; i=i+2)
{
strRes += j.ToString()+": " + #"""" + strnew[i] + " " + strnew[i+1] + #"""" +"\n" ;
j++;
}
Console.Write(strRes);
// print strRes
Related
Let's say I have a string that consists of a person's name:
var name = "Jason, Bruno Mars";
How do I mask the string with X for the name behind the comma and returns:
var name = "Jason, BXXXX MXXX";
I have tried using the following methods but only front characters are masked:
string first, second, output;
bool hasSpace, hasComma;
int int_LENGTH;
var name = "Jason, Bruno Mars";
hasComma = name.Contains(",");
if (hasComma == true)
{
int_LENGTH = name.IndexOf(",");
if (int_LENGTH > 0)
{
first = name.Substring(0, int_LENGTH);
}
second = string.Join(",", name.Split(" ").Skip(1));
hasSpace = second.Contains(" ");
if (hasSpace == true)
{
second = string.Concat(new string('X', 12), second.Substring(second.Length - 4));
output = first + "," + second;
}
}
Anyone has a better idea of how can I achieve the same result in a more efficient way?
Another option, using Regex.Matches to select the name parts except the first letter. The regex collects all string parts separated by a space, skipping what's before the comma.
The collections of Matches is then passed to Linq's Aggregate() method to perform the substitution.
A StringBuilder is used to store the strings generated by its own Replace() method:
string theName = "Jason Et Alt., Bruno Mars And More Names";
var matches = Regex.Matches(theName, #"(?!.*?,)\s+?.(\w+)");
string outName = matches.OfType<Match>().Aggregate(new StringBuilder(theName), (sb, m) =>
sb.Replace(m.Groups[1].Value, new string('X', m.Groups[1].Length))).ToString();
outname = Jason Et Alt., BXXXX MXXX AXX MXXX NXXXX
static string MaskName(string name)
{
string maskedString = string.Empty;
string[] names = name.Split(',');
if (names.Length > 0)
{
maskedString = names[0] + ",";
}
if (names.Length > 1)
{
string[] arrName = names[1].Split(' ');
foreach (string s in arrName)
{
if (s.Length > 0)
maskedString += " " + s[0].ToString().PadRight(s.Length, 'X');
}
}
return maskedString;
}
Using This code..
static string MaskName(string name)
{
string maskedString = string.Empty;
string[] names = name.Split(',');
if (names.Length > 0)
{
maskedString = names[0] + ",";
}
if (names.Length > 1)
{
string[] arrName = names[1].Split(' ');
foreach (string s in arrName)
{
if (s.Length > 0)
maskedString += " " + s[0].ToString().PadRight(s.Length, 'X');
}
}
return maskedString;
}
Output :-
Try This
private string ReturnMaskedName(string name)
{
string temporary = "";
var newname = (name.Split(new string[] { "," }, StringSplitOptions.None)[1].Trim().Split(new String[] { " " }, StringSplitOptions.None));
foreach (string allnames in newname)
{
temporary = temporary + " " + allnames[0].ToString() + new string('X', allnames.Length - 1);
}
return name.Split(new string[] { " " }, StringSplitOptions.None)[0] + " " + temporary;
}
Efficient way of masking without Split, Regex, and using System.Linq:
For C# version < 7.2:
static string MaskName(string name)
{
int indexOfComma = name.IndexOf(',');
if (indexOfComma != -1)
{
char[] temp = name.ToCharArray();
bool isFirstChar = true;
for (int i = indexOfComma + 1; i < temp.Length; i++)
{
if (temp[i] == ' ')
isFirstChar = true;
else if (isFirstChar)
isFirstChar = false;
else
temp[i] = 'X';
}
return new string(temp);
}
else
{
return name;
}
}
For C# version >= 7.2:
static string MaskName(ReadOnlySpan<char> name)
{
int indexOfComma = name.IndexOf(',');
if (indexOfComma != -1)
{
Span<char> temp = stackalloc char[name.Length];
name.CopyTo(temp);
bool isFirstChar = true;
for (int i = indexOfComma + 1; i < temp.Length; i++)
{
if (temp[i] == ' ')
isFirstChar = true;
else if (isFirstChar)
isFirstChar = false;
else
temp[i] = 'X';
}
return new string(temp);
}
else
{
return name.ToString();
}
}
private string MaskName(string name)
{
var parts = name.Split(',');
var subparts = parts[1].Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < subparts.Length; i++)
{
var subpart = subparts[i];
subparts[i] = subpart[0] + new string('X', subpart.Length - 1);
}
return parts[0] + ", " + string.Join(" ", subparts);
}
I want to split a string into smaller parts, not exceeding a string length of 20 characters.
The current code is able to split an input string into an array of strings of length 20. However, this could cut a word.
The current code is:
string[] Array;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < input.Length; i++)
{
if (i % 20 == 0 && i != 0) {
sb.Append('~');
}
sb.Append(input[i]);
}
Array = sb.ToString().Split('~');
For an input of this: Hello. This is a string. Goodbye., the output would be ['Hello. This is a str', 'ing. Goodbye.'].
However, I don’t want the string to be cut if it’s a word. That word should move to the next string in the array. How can I get the following output instead?
['Hello. This is a', 'string. Goodbye.']
First split your sentence on word-boundary:
var words = myString.Split();
Now concatenate words as long as not more than 20 characters are within your current line:
var lines = new List<string> { words[0] };
var lineNum = 0;
for(int i = 1; i < words.Length; i++)
{
if(lines[lineNum].Length + words[i].Length + 1 <= 20)
lines[lineNum] += " " + words[i];
else
{
lines.Add(words[i]);
lineNum++;
}
}
Here is a fiddle for testing: https://dotnetfiddle.net/s0LrFC
Could be more elegant but this will split the string to lines of a maximum number of characters. The words will be kept together unless they exceed the given length.
public static string[] SplitString(string input, int lineLen)
{
StringBuilder sb = new StringBuilder();
string[] words = input.Split(' ');
string line = string.Empty;
string sp = string.Empty;
foreach (string w in words)
{
string word = w;
while (word != string.Empty)
{
if (line == string.Empty)
{
while (word.Length >= lineLen)
{
sb.Append(word.Substring(0, lineLen) + "~");
word = word.Substring(lineLen);
}
if (word != string.Empty)
line = word;
word = string.Empty;
sp = " ";
}
else if (line.Length + word.Length <= lineLen)
{
line += sp + word;
sp = " ";
word = string.Empty;
}
else
{
sb.Append(line + "~");
line = string.Empty;
sp = string.Empty;
}
}
}
if (line != string.Empty)
sb.Append(line);
return sb.ToString().Split('~');
}
To test:
string[] lines = SplitString("This is a test of the string splitter KGKGKJGKGHKJHJKJKHGJHGhghsjagsjasgajsgjahs yes!", 20);
foreach (string line in lines)
{
Console.WriteLine(line);
}
Output:
This is a test of the
string splitter
KGKGKJGKGHKJHJKJKHGJ
HGhghsjagsjasgajsgja
hs yes!
I believe it's faster to split it only at places where it needs to be, instead of every word. With lines.SelectMany(x => Split(x, 80) can be used with multiline texts:
private static IEnumerable<string> Split(string text, int maxLength)
{
var i = 0;
while (i + maxLength < text.Length)
{
var partIndex = text.LastIndexOf(' ', i + maxLength, maxLength);
if (partIndex == -1)
partIndex = i + maxLength;
yield return text[i..partIndex];
i = partIndex + 1;
}
yield return text[i..];
}
I'm doing a school exercise where the user inputs a string and the program must check if it's a palindrome. My only problem currently is that I can't get the loop to ignore whitespaces included in the input string.
Console.Write("Insert string: ");
string input = Console.ReadLine();
char[] charArray = new char[input.Length];
for (int i = 0; i < input.Length; i++)
{
if (Char.IsWhiteSpace(input, i))
{
continue;
}
else
{
charArray[i] += input[i];
}
}
string original = new string(charArray);
I've seemingly tried everything I know, but the whitespaces just get added to the array no matter what I try. Is there a simple solution for this?
[EDIT] Ok you can try the replace method which replaces what you provide with what you want instead (space into no space)
string str = "This is a test";
str = str.Replace(" ", "");
MessageBox.Show(str);
How about using the framework and going this route:
char[] charArray = input.Replace(" ", "").ToCharArray();
Maybe this could work ?
Console.Write("Insert string: ");
string input = Console.ReadLine();
char[] charArray = input.Where(character => !Char.IsWhitespace(character)).ToArray();
When a whitespace is encountered, you never update the value at its position and so it remains a whitespace. So, write to a new array/string:
var newString = string.Empty;
for(int i = 0; i < input.Length; i++)
{
if(!Char.IsWhiteSpace(input[i]))
{
newString += input[i];
}
}
or something more like your code:
Console.Write("Insert string: ");
string input = Console.ReadLine();
char[] charArray = new char[input.Length];
var newString = string.Empty;
for (int i = 0; i < input.Length; i++)
{
if (Char.IsWhiteSpace(input, i))
{
continue;
}
else
{
newString += input[i];
}
}
Console.WriteLine(newString);
how to split a string into multiple lines if more than 37 characters are present?
Example sentence
The Quick Brown Fox Jumped Over The Lazy Dog
It should make it
The Quick Brown Fox Jumped Over The
Lazy Dog
Although the 37th character is 'L'
I want to group by words.
Here is my code
private string sentence(string statement)
{
string completedWord = "";
string temp = "";
string[] wordArray = statement.Split(' ');
for (int i = 0; i < wordArray.Length; i++)
{
temp = completedWord + wordArray[i] + ' ';
if (temp.Length < 37)
{
completedWord = completedWord + wordArray[i] + ' ';
}
else
{
completedWord = completedWord + "\n" + wordArray[i] + ' ';
}
temp = "";
}
return completedWord;
}
Once the sentence is 37 characters, it keeps doing else. I want each line to be 37 before adding \n. This only happens if the sentence is much longer than 37 characters
This should do the trick. I'll use the StringBuilder for convenience, by the way.
static string sentence(string statement)
{
if (statement.Length > 37)
{
var words = statement.Split(' ');
StringBuilder completedWord = new StringBuilder();
int charCount = 0;
if (words.Length > 1)
{
for (int i = 1; i < words.Length - 1; i++)
{
charCount += words[i].Length;
if (charCount >= 37)
{
completedWord.AppendLine();
charCount = 0;
}
completedWord.Append(words[i]);
completedWord.Append(" ");
}
}
// add the last word
if (completedWord.Length + words[words.Length - 1].Length >= 37)
{
completedWord.AppendLine();
}
completedWord.Append(words[words.Length - 1]);
return completedWord.ToString();
}
return statement;
}
You can just do the string substring method as like below,
string WrapText(string statement, int Length)
{
StringBuilder completedWord = new StringBuilder();
completedWord.Append(statement.Substring(0, Length));//cut the specifed legth from long string
completedWord.AppendLine();
completedWord.Append(statement.Substring(Length));//read remainig letters
return completedWord.ToString();
}
I use this:
/// <summary>
/// Wrap lines in strings longer than maxLen by interplating new line
/// characters.
/// </summary>
/// <param name="lines">the lines to process</param>
/// <param name="maxLen">the maximum length of each line</param>
public static string[] wrap_lines(string[] lines, int maxLen)
{
List<string> output = new List<string>();
foreach (var line in lines)
{
var words = line.Split(' ');
string newWord = words[0] + " ";
int len = newWord.Length;
for (int i = 1; i < words.Length; i++)
{
if (len + words[i].Length + 1 > maxLen)
{
len = 0;
newWord += "\n";
i--;
}
else
{
len += words[i].Length + 1;
string ch = i == words.Length - 1 ? "" : " ";
newWord += words[i] + ch;
}
}
output.Add(newWord);
}
return output.ToArray();
}
It assumes that no word is longer than maxLen.
Corrected your for loop:
for (int i = 0; i < wordArray.Length; i++)
{
//temp = completedWord + wordArray[i] + ' '; //remove it
temp = temp + wordArray[i] + ' '; //added
if (temp.Length < 37)
{
completedWord = completedWord + wordArray[i] + ' ';
}
else
{
completedWord = completedWord + "\n"; //corrected
temp = ""; //added
}
//temp = ""; //remove it
}
You could include a field that records the number of lines currently recorded:
string completedWord = "";
string temp = "";
string[] wordArray = statement.Split(' ');
int lines = 1;
for (int i = 0; i < wordArray.Length; i++)
{
temp = completedWord + wordArray[i] + ' ';
if (temp.Length < 37* lines)
{
completedWord = completedWord + wordArray[i] + ' ';
}
else
{
completedWord = completedWord + "\n" + wordArray[i] + ' ';
lines += 1;
}
temp = "";
}
Once you've added the first \n, the string will always exceed 37 chars, so the first if(len<37) test will only return true once.
Instead, you need another var i.e.
string tempLine = "";
Then as you iterate over your word collection, build a line composed of words totaling <= 37 chars via tempLine, once you hit the max, add it to completedWord, then reset tempLine = "" before the next loop.
temp = tempLine + wordArray[i] + ' ';
if (temp.Length < 37)
{
tempLine = tempLine + wordArray[i] + ' ';
}
else
{
completedWord = completedWord + tempLine + "\n";
tempLine = "";
}
temp = "";
Here's my go at it. Its a short little recursive function accepting the string you wish to break into multiple lines, and the maximum length (the cut off point) of each line, as parameters.
It takes a substring of the input text from the beginning to the desired linelength and adds it to an "output" variable. It then feeds the remainder of the input string back in to the function where it keeps recursively calling itself until the length of the remainder is less than the desired linelength, at which point it returns the output variable.
Hope that was clear.
public static string breakString(string s, int lineLength){
string output = "";
if(s.Length > lineLength){
output = output + s.Substring(0, lineLength) + '\n';
string remainder = s.Substring(lineLength, s.Length-lineLength);
output = output + breakString(remainder, lineLength, maxLines);
} else {
output = output + s;
}
return output;
}
The currently accepted answer is overcomplex and not sure if accurate (see comments). A more simple and accurate solution is:
public static class StringExtensions
{
public static string BreakLongLine(this string line, int maxLen, string newLineCharacter)
{
// if there is nothing to be split, return early
if (line.Length <= maxLen)
{
return line;
}
StringBuilder lineSplit = new StringBuilder();
var words = line.Split(' ');
var charCount = 0;
for (var i = 0; i < words.Length; i++)
{
if (charCount + words[i].Length >= maxLen)
{
// '>=' and not '>' because I need to add an extra character (space) before the word
// and last word character should not be cut
lineSplit.Append(newLineCharacter);
charCount = 0;
}
if (charCount > 0)
{
lineSplit.Append(' ');
charCount++;
}
lineSplit.Append(words[i]);
charCount += words[i].Length;
}
return lineSplit.ToString();
}
}
Please note that this solution:
do not leave spaces at the end of a line;
code is cleaner. For example, has fewer conditions and it returns early to improve code readiness
I also cover this method with unit tests so you can see that works:
public class StringExtensionsTests
{
[Fact]
public void SplitIntoTwoLines()
{
// arrange
const string longString = "Four words two lines";
// act
var resultString = longString.BreakLongLine(10, "\n");
// assert
Assert.Equal("Four words\ntwo lines", resultString);
}
[Fact]
public void SplitIntoThreeLines()
{
// arrange
const string longString = "Four words two lines";
// act
var resultString = longString.BreakLongLine(9, "\n");
// assert
Assert.Equal("Four\nwords two\nlines", resultString);
}
// https://stackoverflow.com/questions/15793409/how-to-split-a-string-into-multiple-lines-if-more-than-37-characters-are-present
[Fact]
public void StackOverflowExample()
{
// arrange
const string longString = "The Quick Brown Fox Jumped Over The Lazy Dog";
// act
var resultString = longString.BreakLongLine(37, "\n");
// assert
Assert.Equal("The Quick Brown Fox Jumped Over The\nLazy Dog", resultString);
}
}
I have a textbox with multiline enabled, and want to add a string at the beginning and end of
each line, so every line would be changed to
a + line + b
Now I know it has to do with a foreach loop, but don't know how to write it out.
Well, the Lines property is probably the one you want. Three options:
string[] lines = textBox.Lines;
for (int i = 0; i < lines.Length; i++)
{
lines[i] = a + lines[i] + b;
}
textBox.Lines = lines;
Or:
textBox.Lines = Array.ConvertAll(textBox.Lines, line => a + line + b);
Or:
textBox.Lines = textBox.Lines
.Select(line => a + line + b)
.ToArray();
You can use a replace on the entire text:
text = a + text.Replace(Environment.NewLine, b + Environment.NewLine + a) + b;
Since you mentioned foreach, here's another way.
var newLines = new List<string>(textBox1.Lines.Length);
foreach (string line in textBox1.Lines)
newLines.Add(a + line + b);
textBox1.Lines = newLines.ToArray();
Here is what i use to add the characters a and b to the beginning and the end to a string that contains a bunch of lines :
public string Script;
string[] lines = Script.Split(new[] { '\r', '\n' });
for (int i = 0; i < lines.Length; i++)
{
lines[i] = a + lines[i] + b;
if (!lines[i].Equals("\"\"+"))
{
Console.WriteLine(lines[i]);
Result += lines[i]+"\n";
}
}