I am trying to remove the first line of a paragraph when the total lines exceed a predetermined number of entries. This is for a kind of chat window and I do not want too many lines displayed at one time.
private Paragraph paragraph = new Paragraph();
public void WriteMessage(string output)
{
string outputFormat = string.Format("{0}", output);
string[] parts = output.Split(new char[]{':'}, 2);
string user = parts[0];
string[] username = parts[0].Split('!');
paragraph.Inlines.Add(new Run(username[0].Trim() + ": "){Foreground = UserColor});
paragraph.Inlines.Add(new Run(parts[1]) { Foreground = MessageColor});
paragraph.Inlines.Add(new LineBreak());
if (paragraph.Inlines.Count >= 50) {
//???
//The count does not actually count lines the way I would expect.
}
}
Not sure of the easiest way to do this, everything I have tried thus far has not worked.
Suggest you use List verus array. It gives you some functionality you need.
public List<string> TrimParagraph(List<string> paragraph)
{
int count = paragraph.Count;
if (count > 50)
paragraph = paragraph.Skip(count - 50).ToList();
return paragraph;
}
Edit... Use something like this when constructing your paragraph object.
Solved it by creating a FlowDocument and adding the paragraph to the block. Then each entry is it's own block and it retains the original formatting.
private Paragraph paragraph = new Paragraph();
_rtbDocument = new FlowDocument(paragraph);
public void WriteMessage(string output)
{
string outputFormat = string.Format("{0}", output);
string[] parts = output.Split(new char[]{':'}, 2);
string user = parts[0];
string[] username = parts[0].Split('!');
Paragraph newline = new Paragraph();
newline.LineHeight = 2;
newline.Inlines.Add(new Run(username[0].Trim() + ": ") { Foreground = UserColor });
newline.Inlines.Add(new Run(parts[1]) { Foreground = MessageColor });
_rtbDocument.Blocks.Add(newline);
if (_rtbDocument.Blocks.Count > 10)
{
_rtbDocument.Blocks.Remove(_rtbDocument.Blocks.FirstBlock);
}
}
Related
I am trying to randomly read a huge .txt file. It has tons of paragraphs separated by a full line of empty space prior and post each paragraph. I would like each time I randomly read that it pulls up a full intact paragraph without any characters or words missing for the sake of context. I appreciated the help in advance.
I added a for loop just to test it out and see if I can at some point include a way to recognize consecutively running empty space. That would only work post already selected the starting point obviously if applied.
public static string GetRandomLine(string filename)
{
var lines = File.ReadAllLines(filename);
var lineNumber = _rand.Next(0, lines.Length);
string reply = lines[lineNumber];
return reply ;
}
Try the following:
public static string[] GetRandomParagraph(string filePath)
{
if (File.Exists(filePath))
{
string text = File.ReadAllText(filePath);
string[] paragraphs = text.Split(new string[] { "\n\n" }, StringSplitOptions.None);
return paragraphs[new Random().Next(0, paragraphs.Length)].Split('\n');
}
else
throw new FileNotFoundException("The file was not found", filePath);
}
I really hope that is that what you are looking for.
// This builds a list of Paragraph first
public static List<string> GetParagraphs(string filename)
{
var paragraphs = new List<string>();
var lines = File.ReadAllLines(filename);
bool newParagraph = true;
string CurrentParagraph = string.Empty;
// Build the list of paragraphs by adding to the currentParagraph until empty lines and then starting a new one
foreach(var line in lines)
{
if(newParagraph)
{
CurrentParagraph = line;
newParagraph = false;
}
else
{
if(string.IsNullOrWhiteSpace(line))// we're starting a new paragraph, add it to the list of paragraphs and reset current paragraph for next one
{
paragraphs.Add(CurrentParagraph);
CurrentParagraph = string.Empty;
newParagraph = true;
}
else // we're still in the same paragraph, add the line to current paragraph
{
newParagraph += (Environment.NewLine + line);
}
}
}
// Careful, if your file doesn't end with a newline the last paragraph won't count as one, in that case add it manually here.
}
public static Random rnd = new Random();
// And this returns a random one
public static string GetRandomParagraph(string fileName)
{
var allParagraphs = GetParagraphs(filename);
allParagraphs[rnd.Next(0,allParagraphs.length-1)]; // pick one of the paragraphs at random, stop at length-1 as collection indexers are 0 based
}
Note that if you're always reading from the same file this could be much faster by only calling GetParagraphs once and keeping the list of paragraphs in memory.
Try this:
public static string GetRandomLine(string filename)
{
var lines = File.ReadAllLines(filename);
var lineNumber = _rand.Next(0, lines.Length - 1);
var blankBefore = lineNumber;
var blankAfter = lineNumber + 1;
string reply = "";
while (lines[blankBefore].Length > 0)
{
blankBefore--;
}
while (lines[blankAfter].Length != 0)
{
blankAfter++;
}
for ( int i = blankBefore + 1; blankBefore < blankAfter; blankBefore++)
{
reply += lines[i];
}
return reply;
}
Based on your description, I'm assuming the file begins and ends with a blank line. By setting the exclusive upper bound of the random line to be one less than the length of lines, you avoid the chance of the random line being the last line of the file. If the random line is a blank line, blankBefore will be the index of that line, otherwise, it will be back tracked until it reaches the previous blank. blankAfter starts as the index of the next line after the random line and if that line is not blank, blankAfter is increased until it is the index of the next blank line.
Once you have the index of the blank lines before and after the target paragraph, simply append the lines between them to reply.
If the first and last lines of the file are not blank, you would need to verify that blankBefore and blankAfter remain within the bounds of the array.
I made some modifications to the code provided above by #TheCoderCrab. I turned the method to a string method so it would return a string. I simply added a for loop append all the characters of the paragraph array on to a new string which returns it to the main. Thank you.
public static string GetRandomParagraph(string filePath)
{
if (File.Exists(filePath))
{
string text = File.ReadAllText(filePath);
string[] paragraphs = text.Split(new string[] { "\n\n" }, StringSplitOptions.None);
string [] paragraph = paragraphs[new Random().Next(0, paragraphs.Length)].Split('\n');
//Added a for loop to build the string out of all the characters in the 'paragraph' array index.
string pReturn = "";
for (int a = 0; a < paragraph.Length; a++)
{
//Loop through and consecutively append each character of mapped array index to a return string 'pReturn'
pReturn = pReturn + paragraph[a].ToString();
}
return pReturn;
}
else
throw new FileNotFoundException("The file was not found", filePath);
}
To get intact paragraphs
public static string GetRandomParagraph(string fileName)
{
/*
Rather than reading all the lines, read all the text
this gives you the ability to split by paragraph
*/
var allText = File.ReadAllText(fileName);
// Use as separator for paragraphs
var paragraphSeparator = $"{Environment.NewLine}{Environment.NewLine}";
// Treat large white spaces after a new line as separate paragraphs
allText = Regex.Replace(allText, #"(\n\s{3,})", paragraphSeparator);
// Split the text into paragraphs
var paragraphs = allText.Split(paragraphSeparator);
// Get a random index between 0 and the amount of paragraphs
var randomParagraph = new Random().Next(0, paragraphs.Length);
return paragraphs[randomParagraph];
}
I have 2 strings. These 2 strings can differ in size. I want to look at these 2 strings finding matching sequences. Once I find a change I want to print that word in Capital and then continue on in my string until I find another change and so on. I'm not sure how I would go about this I tried looking at words as a whole but I'm having issues with that. Basically I will have 2 string something like this string one="This is a new value" and string two= "This This is a new also brand value". I want go though each string from the start and find the matching sequences e.g. "This is" stop at string realise it has changed as string was added change it to upper case and then carry on. Expected output ="THIS this is a new ALSO BRAND value "
Some code I was trying. I don't think this is the right approach.
static void Main(string[] args)
{
string one = "This is a new value";
string two = "This This is a new also brand value";
var coll = two.Split(' ').Select(p => one.Contains(p) ? p : p.ToUpperInvariant());
Console.WriteLine(string.Join(" ", coll));
Console.ReadKey();
}
Is this what you're looking for? The description isn't fantastic, but judging by the answers this seems to be in the same ballpark, and it uses LINQ for less code and complication.
class Program
{
static void Main(string[] args)
{
string one = "This is text one";
string two = "This is string text two not string one";
var coll = two.Split(' ').Select(p => one.Contains(p) ? p : p.ToUpperInvariant());
Console.WriteLine(string.Join(" ", coll)); // This is STRING text TWO NOT STRING one
Console.ReadKey();
}
}
You can break this out to a separate method and pass your variables in as parameters.
You can convert string to char array and compare chars one by one. You can use the following code i guess.
string one = "this is string one";
string two = "this is string one or two";
char[] oneChar = one.ToCharArray();
char[] twoChar = two.ToCharArray();
int index = 0;
List<char> Diff = new List<char>();
if (oneChar.Length > twoChar.Length)
{
foreach (char item in twoChar)
{
if (item != oneChar[index])
Diff.Add(item);
index++;
}
for (int i = index; i < oneChar.Length; i++)
{
Diff.Add(oneChar[i]);
}
}
else if (oneChar.Length < twoChar.Length)
{
foreach (char item in oneChar)
{
if (item != twoChar[index])
Diff.Add(twoChar[index]);
index++;
}
for (int i = index; i < twoChar.Length; i++)
{
Diff.Add(twoChar[i]);
}
}
else//equal length
{
foreach (char item in twoChar)
{
if (item != oneChar[index])
Diff.Add(item);
}
}
Console.WriteLine(Diff.ToArray());//" or two"
Is that what you need? (Updated)
var value1 = "This is a new Value";
var value2 = "This is also a new value";
var separators = new[] { " " };
var value1Split = value1.Split(separators, StringSplitOptions.None);
var value2Split = value2.Split(separators, StringSplitOptions.None);
var result = new List<string>();
var i = 0;
var j = 0;
while (i < value1Split.Length && j < value2Split.Length)
{
if (value1Split[i].Equals(value2Split[j], StringComparison.OrdinalIgnoreCase))
{
result.Add(value2Split[j]);
i++;
j++;
}
else
{
result.Add(value2Split[j].ToUpper());
j++;
}
}
Console.WriteLine(string.Join(" ", result));
Console.ReadKey();
Note that if for value1="This is a new Value" and value2="This is also a new value" output should be "This is ALSO a new value" than for value1="This is text one" and value2="This is string text two not string one" output will be "This is STRING text TWO NOT STRING one", not "This is STRING TEXT TWO NOT STRING ONE" as you mentioned before.
I have an ASP.NET web application. This application renders out glossary type items, similar to the following:
This goes through all the letters in the alphabet for items. I am rendering this out and appending it directly to a Controls collection in a Server Control using the following:
List<char> alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray().ToList();
foreach (char c in alpha)
{
Label lblAlphaCharacter = new Label();
lblAlphaCharacter.Font.Size = 24;
lblAlphaCharacter.Font.Bold = true;
lblAlphaCharacter.Text = c.ToString(CultureInfo.InvariantCulture);
Controls.Add(lblAlphaCharacter);
Controls.Add(new LiteralControl("<p>"));
FilterOnAlphaCharacter(this, Page, c);
Controls.Add(new LiteralControl("<p>"));
}
private static void FilterOnAlphaCharacter(Control control, Page page, char character)
{
foreach (List<Things> item in items)
{
string title = item.Title;
string description = item.Definition;
HyperLink link = new HyperLink();
link.Text = title;
control.Controls.Add(link);
Label lblDescription = new Label();
lblDescription.Text = string.Format(" - {0}", description);
control.Controls.Add(lblDescription);
}
}
}
I am trying to, depending on the content, equally split this, so that it looks like this:
This can have different amounts of items. So in reality, there could be 25 entries under "A", and perhaps 1 under "Z". The above is just an example, it goes through all letters A-Z. The expected result would be based on the amount of content, it would equally split between two columns. I have to do this server-side (I was thinking using Table or HtmlTable and related objects).
Howe would you implement a solution for splitting the content equally in a Table or the likes (sort of indifferent on approach).
try this:
//it shows the number of line that inserting during the process
private int _inserteditemCount;
//its number of items in each column
private int _itemsCount;
//line height use for determine paragraph line height
private const string Lineheight = "30px";
protected void Page_Load(object sender, EventArgs e)
{
_inserteditemCount = 0;
var alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
//you can do this query in data access layer
var listCountcount = new Thingsclass().GetThings().Count;
//Count of rows on dictionary + number of leters
_itemsCount = (listCountcount + alpha.Count()) / 2;
var leftdiv = new HtmlGenericControl("div");
var rightdiv = new HtmlGenericControl("div");
//you can change this styles
leftdiv.Style.Add("display", "inline-block");
leftdiv.Style.Add("width", "50%");
leftdiv.Style.Add("float", "Left");
rightdiv.Style.Add("display", "inline-block");
rightdiv.Style.Add("float", "right");
rightdiv.Style.Add("width", "50%");
foreach (var c in alpha)
{
var lblAlphaCharacter = new Label();
lblAlphaCharacter.Font.Size = 24;
lblAlphaCharacter.Font.Bold = true;
lblAlphaCharacter.Text = c.ToString(CultureInfo.InvariantCulture);
var control = _inserteditemCount <= _itemsCount ? leftdiv : rightdiv;
var paragraph = new HtmlGenericControl("p");
paragraph.Style.Add("line-height", Lineheight);
paragraph.Controls.Add(lblAlphaCharacter);
control.Controls.Add(paragraph);
FilterOnAlphaCharacter(leftdiv, rightdiv, c.ToString());
_inserteditemCount++;
}
Panel1.Controls.Add(leftdiv);
Panel1.Controls.Add(rightdiv);
}
private void FilterOnAlphaCharacter(Control leftctr, Control rightctr, string character)
{
//you can do this query in data access layer
var items = new Thingsclass().GetThings().Where(c => c.chara.ToLower().Equals(character.ToLower()));
foreach (var item in items)
{
var paragraph = new HtmlGenericControl("p");
paragraph.Style.Add("line-height", Lineheight);
var control = _inserteditemCount <= _itemsCount ? leftctr : rightctr;
var title = item.Title;
var description = item.Description;
var link = new HyperLink { Text = title };
paragraph.Controls.Add(link);
var lblDescription = new Label { Text = string.Format(" - {0}", description) };
paragraph.Controls.Add(lblDescription);
_inserteditemCount++;
control.Controls.Add(paragraph);
}
}
Is there any way to sort lines in winforms richtextbox preserving RTF formatting?
var lines = edit.Lines.OrderBy(s => s);
edit.Lines = lines.ToArray();
do the job fine, but, obviously, loosing any RTF formatting.
I have slightly changed the snippet of TaW:
1. Adding "unique" might break the very first line formatting
2. Besides "\par" tag there is also "\pard"
Here is a snippet (thanks again to TaW!):
private void cmdSort_Click(object sender, EventArgs e)
{
const string PARD = "\\pard";
var pard = Guid.NewGuid().ToString();
var pos1 = edit.Rtf.IndexOf(PARD, StringComparison.Ordinal) + PARD.Length;
if (pos1 < 0) return;
var header = edit.Rtf.Substring(0, pos1);
var body = edit.Rtf.Substring(pos1);
body = body.Replace("\\pard", pard);
var lines = body.Split(new[] { "\\par" }, StringSplitOptions.None);
var lastFormat = "";
var sb = new StringBuilder();
var rtfLines = new SortedList<string, string>();
foreach (var line in lines)
{
var ln = line.Replace(pard, "\\pard");
var temp = ln.Replace("\r\n", "").Trim();
if (temp.Length > 0 && temp[0] != '\\')
{
rtfLines.Add(temp.Trim(), lastFormat + " " + ln);
}
else
{
var pos2 = temp.IndexOf(' ');
if (pos2 < 0)
{
rtfLines.Add(temp.Trim(), ln);
}
else
{
rtfLines.Add(temp.Substring(pos2).Trim(), ln);
lastFormat = temp.Substring(0, pos2);
}
}
}
foreach (var key in rtfLines.Keys.Where(key => key != "}"))
{
sb.Append(rtfLines[key] + "\\par");
}
edit.Rtf = header + sb;
}
Here is a code snippet that seems to work if the file has neither images nor tables embedded..
It uses two RTF boxes. In my tests they sorted alright and kept all formatting intact.
private void button4_Click(object sender, EventArgs e)
{
string unique = Guid.NewGuid().ToString() ;
richTextBox1.SelectionStart = 0;
richTextBox1.SelectionLength = 0;
richTextBox1.SelectedText = unique;
int pos1 = richTextBox1.Rtf.IndexOf(unique);
if (pos1 >= 0)
{
string header = richTextBox1.Rtf.Substring(0, pos1);
string header1 = "";
string header2 = "";
int pos0 = header.LastIndexOf('}') + 1;
if (pos0 > 1) { header1 = header.Substring(0, pos0); header2 = header.Substring(pos0); }
// after the header comes a string of formats to start the document
string[] formats = header2.Split('\\');
string firstFormat = "";
string lastFormat = "";
// we extract a few important character formats (bold, italic, underline, font, color)
// to keep with the first line which will be sorted away
// the lastFormat variable holds the last formatting encountered
// so we can add it to all lines without formatting
// (and of course we are really talking about paragraphs)
foreach (string fmt in formats)
if (fmt[0]=='b' || ("cfiu".IndexOf(fmt[0]) >= 0 && fmt.Substring(0,2)!="uc") )
lastFormat += "\\" + fmt; else firstFormat += "\\" + fmt;
// add the rest to the header
header = header1 + firstFormat;
// now we remove our marker from the body and split it into paragraphs
string body = richTextBox1.Rtf.Substring(pos1);
string[] lines = body.Replace(unique, "").Split(new string[] { "\\par" }, StringSplitOptions.None);
StringBuilder sb = new StringBuilder();
// the soteredlist will contain the unformatted text as key and the formatted one as valaue
SortedList<string, string> rtfLines = new SortedList<string, string>();
foreach (string line in lines)
{
// cleanup
string line_ = line.Replace("\r\n", "").Trim();
if (line_[0] != '\\' ) rtfLines.Add(line_, lastFormat + " " + line);
else
{
int pos2 = line_.IndexOf(' ');
if (pos2 < 0) rtfLines.Add(line_, line);
else
{
rtfLines.Add(line_.Substring(pos2).Trim(), line);
lastFormat = line_.Substring(0, pos2);
}
}
}
foreach (string key in rtfLines.Keys) if (key != "}") sb.Append(rtfLines[key] + "\\par");
richTextBox2.Rtf = header + sb.ToString();
}
Of course this is really q&d and not ready for serious production; but it looks like a start.
EDIT 2: I changed the code to fix a bug with the first line's format and added some comments. This should work a lot better, but is still a hack that must be adapted to the real input files..
RichTextBox has a property Rtf that would keep RTF formatting.
[BrowsableAttribute(false)]
public string Rtf { get; set; }
I have this code :
private void BtnScrambleText_Click(object sender, EventArgs e)
{
textBox1.Enabled = false;
BtnScrambleText.Enabled = false;
StringBuilder sb = new StringBuilder();
var words = textBox1.Text.Split(new char[] { ' ' });
for (int i = 0; i < words.Length; i++)
{
if (string.IsNullOrEmpty(words[i]))
{
sb.Append(words[i]);
}
else
{
ScrambleTextBoxText scrmbltb = new ScrambleTextBoxText(words[i]);
scrmbltb.GetText();
sb.Append(scrmbltb.scrambledWord);
}
}
textBox2.AppendText(sb.ToString());
}
For example in textBox1 i did typed pressed the space bar key 7 times and then typed some words and then 5 spaces again and a word:
danny hi hello daniel hello
So lets say danny is after 7 spaces from the beginning in textBox1 and between daniel and hello there are more 5 spaces.
In my code i did:
if (string.IsNullOrEmpty(words[i]))
{
sb.Append(words[i]);
}
But that never will happen and its not right.
I wanted to check that if before or after a word in the textBox there is any space/s add the space/s to the sb variable.
So in the end textBox2 content will be the same as in textBox1 with the same number of spaces between the words.
Now textBox2 looks like a long one string of words without any spaces between them.
My problem is how to add the same spaces between the words from textBox1 ?
I simplified your code a little, but you should find it easy to apply in your situation. The problem comes from the fact that you are losing the spaces when you do the split and they are not being added back in. The solution is to use "String.Join" when you have the finished collection of strings. In this case since you know the output size is the same as the input size, I don't see any reason to use the stringbuilder. Just use an array you size to the input.
string inputText = "This is a test";
var words = inputText.Split(new char[] { ' ' });
var outputWords = new string[words.Length];
for (int i = 0; i < words.Length; i++)
{
if (string.IsNullOrEmpty(words[i]))
{
outputWords[i] = words[i];
}
else
{
outputWords[i] = Scramble(words[i]);
}
}
string outputText = string.Join(" ",outputWords);
This statement is absolutely useless:
if (string.IsNullOrEmpty(words[i]))
{
sb.Append(words[i]);
}
It seems you need something like this (not tested):
private void BtnScrambleText_Click(object sender, EventArgs e)
{
textBox1.Enabled = false;
BtnScrambleText.Enabled = false;
StringBuilder sb = new StringBuilder();
var words = Regex.Split(textBox1.Text, #"(?=(?<=[^\s])\s+)");
foreach (string word in words)
{
ScrambleTextBoxText scrmbltb = new ScrambleTextBoxText(word.Trim());
scrmbltb.GetText();
sb.Append(word.Replace(word.Trim(), scrmbltb.scrambledWord));
}
textBox2.AppendText(sb.ToString());
}
Regex.Split(textBox1.Text, #"(?=(?<=[^\s])\s+)") splits the input string with preserving spaces.
This the easy form
string text=mytextbox.Text;
while(text.Contains(" ")) //while two spaces
text=text.Replace(" "," "); //remove two spaces
If i got it right, your problem is to keep the exact number of spaces between the then scrambled words.
var words = string.Split(new char[]{' '}, StringSplitOptions.None); // this keeps the spaces as "epmty words"
var scrambled = words.Select(w => { if (String.IsNullOrEmpty(w))
return w;
else {
ScrambleTextBoxText scrmbltb = new ScrambleTextBoxText(w);
scrmbltb.GetText();
return scrmbltb.scrambledWord;
}
});
var result = string.Join(" ", scrambled);