If I have a RichTextBox that is loaded from a file containg:
TEXT MORETEXT 10.505 100.994 0
TEXT MORETEXT -5.132 -12.994 90
TEXT MORETEXT 100.001 -8.994 270
and a TextBox that contains whatever the user enters in the textbox. Let's say the user enters "10.005".
My question is, how do I take this value and add it to the 3rd column containing the values 10.505, -5.132, 100.001. Once it is added, I would like to take the value and Replace the old value in the string. SO the updated RichTextBox would look like this.
TEXT MORETEXT 20.510 100.994 0
TEXT MORETEXT 4.873 -12.994 90
TEXT MORETEXT 110.006 -8.994 270
RIGHT NOW I am able to strip the strings from the RichTextBox by using this code:
private void calculateXAndYPlacementTwo()
{
// Reads the lines in the file to format.
var fileReader = File.OpenText(filePath);
// Creates a list for the lines to be stored in.
var fileList = new List<string>();
// Adds each line in the file to the list.
while (true)
{
var line = fileReader.ReadLine();
if (line == null)
break;
fileList.Add(line);
}
// Creates new lists to hold certain matches for each list.
var xyResult = new List<string>();
var xResult = new List<string>();
var yResult = new List<string>();
// Iterate over each line in the file and extract the x and y values
fileList.ForEach(line =>
{
Match xyMatch = Regex.Match(line, #"(?<x>-?\d+\.\d+)\s+(?<y>-?\d+\.\d+)");
if (xyMatch.Success)
{
// grab the x and y values from the regular expression match
String xValue = xyMatch.Groups["x"].Value;
String yValue = xyMatch.Groups["y"].Value;
// add these two values, separated by a space, to the "xyResult" list.
xyResult.Add(String.Join(" ", new[]{ xValue, yValue }));
// Adds the values into the xResult and yResult lists.
xResult.Add(xValue);
yResult.Add(yValue);
// Place the 'X' and 'Y' values into the proper RTB.
xRichTextBox.AppendText(xValue + "\n");
yRichTextBox.AppendText(yValue + "\n");
}
});
}
To get the values in the xRichTextBox looking like:
10.505
-5.132
100.001
and the yRichTextBox looking like:
100.994
-12.994
-8.994
But I do not know how to turn those into values that can have addition used on them...
EDIT:
I have messed around with this some more... I am now using this code (below) to try to accomplish what I need it to do. This is only for the "X" (3rd column).
HOWEVER THIS CODE IS NOT WORKING (it concats the user input to the end of the xRichTextBox instead of mathematically adding it to each line..)
The xDisplacementTextBox is the user input and the xRichTextBox is the stripped values from the main string.
StringBuilder stringBuilder = new StringBuilder();
string[] Lines = xRichTextBox.Text.Split('\n');
double d = double.Parse(xDisplacementTextBox.Text);
for(int i = 0; i < Lines.Length; ++i)
{
string newThing = double.Parse((Lines[i]) + d).ToString();
stringBuilder.AppendLine(newThing);
}
xRichTextBox.Text = stringBuilder.ToString();
This is also not letting me enter in values that have decimals (ie. 50.005)..
Look at double.Parse - as in
double x = double.Parse(xValue);
To expand, and do your work for you...
double d = double.Parse(xDisplacementTextBox.Text);
string[] Lines = xRichTextBox.Text.Split('\n');
for(int i = 0; i < Lines.Length; ++i)
{
Match lineMatch = Regex.Match(lines[i], #"^(?<p>.*)(?<x>-?\d+\.\d+)(?<y>\s+-?\d+\.\d+\s+-?\d+\.\d+)$");
if (lineMatch.Success)
{
double xValue = double.Parse(lineMatch.Groups["x"].Value) + d;
lines[i] = lineMatch.Groups["p"] + xValue + lineMatch.Groups["p"];
}
}
xRichTextBox.Text = string.Join(lines, '\n');
Too many strings and not enough data structures.
This looks like a data structure:
TEXT MORETEXT 10.505 100.994 0
TEXT MORETEXT -5.132 -12.994 90
TEXT MORETEXT 100.001 -8.994 270
So, create a class that holds
"Text" string
"MoreText" string
10.505 - double (let's call this prop1)
100.994 - double
0 - int
I'm speculating on the data values here.
Load the List<> of your class into memory.
Then, apply the text box value to your list of object every time the value changes.
PsuedoCode:
foreach(class c in List<>)
{
c.prop1 = c.prop1 + (double)Textbox.value;
}
Override ToString() in your class and display the object as needed in the rich text box.
Personally I would use a list box to display the objects.
Related
private void Parse_Click(object sender, EventArgs e)
{
for (int i = 0; i < keywordRanks.Lines.Length; i++)
{
int p = keywordRanks.Lines.Length;
MessageBox.Show(p.ToString());
string splitString = keywordRanks.Lines[i];
string[] s = splitString.Split(':');
for (int j = 0; j < keywords.Lines.Length; j++)
{
string searchString = keywords.Lines[j];
if (s[0].Equals(searchString))
{
richTextBox1.Lines[j] = searchString + ':' + s[1];
}
}
}
}
I have an issue with inserting string in a particular line. I have 2 multi line TextBoxes and one RichTextBox.
My application will search for the strings from textbox1 to textbox2 line by line and need to insert those matched values in a RichTextBox control but in the exact index position where it found in textbox2.
If the value found in 5th line of textbox2 then that found line need to be inserted in the RichTextBox 5th line.
Some how my code is not working. I tried a lot but no luck. The code I need something like below but its not working and an IndexOutOfBound exception is raised.
richTextBox1.Lines[j] = searchString + ':' + s[1];
Your RichTextBox must contain all the needed lines before you can set the value using the line index.
If the Control contains no text or line breaks (\n), no lines are defined and any attempt to set a specific Line[Index] value will generate an IndexOutOfRangeException exception.
Here, I'm using a pre-built array, sized as the number of possible matches (the Lines.Length of the keywords TextBox). All matches found are stored here in the original position. The array is then assigned to the RichTextBox.Lines property.
Note: directly using and pre-setting the RichTextBox.Lines won't have effect: the text will remain empty.
string[] MatchesFound = new string[keywords.Lines.Length];
foreach (string currentSourceLine in keywordRanks.Lines)
{
string[] SourceLineValue = currentSourceLine.Split(':');
var match = keywords.Lines.ToList().FindIndex(s => s.Equals(SourceLineValue[0]));
if (match > -1)
MatchesFound[match] = currentSourceLine;
}
richTextBox1.Lines = MatchesFound;
Source Matches Result
(keywordRanks) (keywords) (RichTextBox)
-------------------------------------------
aand:1 aand aand:1
cnd:5 this one
cnds:9 cnds cnds:9
fan:2 another one
gst:0 cnd cnd:5
fan fan:2
I have a search function that searches keywords in a block of text and displays a truncated version of the results. My problem is that it will not show the searched keyword if its near the end.
For example.
Text = "A block of text is text that is grouped together in some way, such as with the use of paragraphs or blockquotes on a Web page. Often times, the text takes on the shape of a square or rectangular block"
I search for "times" with
text = text.Substring(0, 100) + "...";
It will return
"A block of text is text that is grouped together in some way, such as with the use of paragraphs or..."
Is there a way to return 100 characters before and after the searched keyword?
You can do this,
string s = "A block of text is text that is grouped together in some way, such as with the use of paragraphs or";
string toBeSearched = "grouped";
int firstfound = s.IndexOf(toBeSearched);
if (firstfound != -1 )
{
string before = s.Substring(0 , firstfound);
string after = s.Substring(firstfound + toBeSearched.Length);
}
DEMO
string s = "A block of text is text that is grouped together in some way, such as with the use of paragraphs or";
string wordtoSearch = "block";
int firstfound = s.IndexOf(wordtoSearch);
// If the index of the first letter found is greater than 100, get the 100 letters before the found word and 100 letters after the found word
if (firstfound > 100)
{
string before = s.Substring(firstfound , firstfound-100);
string after = s.Substring(firstfound + wordtoSearch.Length, 100);
Console.WriteLine(before);
Console.WriteLine(after);
}
//// If the index of the first letter found is less than 100, get the letters before the found word and 100 letters after the found word
if(firstfound < 100)
{
string before = s.Substring(0, firstfound);
Console.WriteLine(before);
if(s.Length >100)
{
string after = s.Substring(firstfound + wordtoSearch.Length, 100);
Console.WriteLine(after);
}
else
{
string after = s.Substring(firstfound + wordtoSearch.Length);
Console.WriteLine(after);
}
}
You can do something like this as well, making it a bit more reusable and able to match multiple instances of the keyword
string input = "A block of text is text that is grouped together in some way, such as with the use of paragraphs or blockquotes on a Web page. Often times, the text takes on the shape of a square or rectangular block";
int buffer = 30; // how much do you want to show before/after
string match = "times";
int location = input.IndexOf(match);
while (location != -1) {
// take buffer before and after:
int start = location - Math.Min (buffer , location); // don't take before start
int end = location + match.Length
+ Math.Min( buffer, input.Length - location - match.Length); // don't take after end
Console.WriteLine("..." + input.Substring(start, end-start) + "...");
location = input.IndexOf(match,location+1);
}
Giving you an output of
...A block of text is text that is gro...
...with the use of paragraphs or blockquotes on a Web page. Often ...
...pe of a square or rectangular block...
I want to split a string into an array at a point where the text wraps for a given width
Suppose this is the string.
I want text width to be 300 :
I want to split a string into an array at a point where the text wraps for a given width
And use a function, something like this :
Text.SplitAtWrap(300,Text)
This is the output i want :
(0) I want to split a string into an
(1) array at a point where the text
(2) wraps for a given width
Edit:
I would probably have to take the font into account, so probably have to use Drawing.Graphics.
There is an answer here (please give credit to whom deserve it)
public List<string> GetSubstrings(string toSplit, int maxLength, Graphics graph, Font font)
{
List<string> substrings = new List<string>();
string[] words = toSplit.Split(" ".ToCharArray());
string oneSub = "";
foreach (string oneWord in words)
{
string temp = oneSub + oneWord + " ";
if (graph.MeasureString( temp, font).Width > maxLength)
{
substrings.Add(oneSub);
oneSub = oneWord + " ";
}
else
oneSub = temp;
}
substrings.Add(oneSub);
return substrings;
}
Basically, your input string is divided in its component words, then each word is measured using the graphics object and a reference font. If the length of the current word plus the previous words is less than the required length the word is rejoined together. Otherwise the resulting string is added to a list of strings to be returned to the caller.
Need some ideas how to solve this problem.
I have a template file what describes the line in the text file. For example:
Template
[%f1%]|[%f2%]|[%f3%]"[%f4%]"[%f5%]"[%f6%]
Text file
1234|1234567|123"12345"12"123456
Now i need to read in the fields from the text file. In the template file fields are described with [%some name%]. Allso in the template file there is set what the field separators are, in this example here there are | and ". The lenght of the fields can change through different files but the separators will stay the same. What would be the best way to read in the template and by template read in the text file?
EDIT: Text file has multiple rows, like this:
1234|1234567|123"12345"12"123456"\r\n
1234|field|123"12345"12"asdasd"\r\n
123sd|1234567|123"asdsadf"12"123456"\r\n
45gg|somedata|123"12345"12"somefield"\r\n
EDIT2: Ok, lets make it even harder. Some fields can contain binary data and i know the starting and end position of the binary data field. I should be able to mark those fields in the template and then the parser will know that this field is binary. How to solve this problem?
I would create a regex based on the template and then parse the text file using that:
class Parser
{
private static readonly Regex TemplateRegex =
new Regex(#"\[%(?<field>[^]]+)%\](?<delim>[^[]+)?");
readonly List<string> m_fields = new List<string>();
private readonly Regex m_textRegex;
public Parser(string template)
{
var textRegexString = '^' + TemplateRegex.Replace(template, Evaluator) + '$';
m_textRegex = new Regex(textRegexString);
}
string Evaluator(Match match)
{
// add field name to collection and create regex for the field
var fieldName = match.Groups["field"].Value;
m_fields.Add(fieldName);
string result = "(.*?)";
// add delimiter to the regex, if it exists
// TODO: check, that only last field doesn't have delimiter
var delimGroup = match.Groups["delim"];
if (delimGroup.Success)
{
string delim = delimGroup.Value;
result += Regex.Escape(delim);
}
return result;
}
public IDictionary<string, string> Parse(string text)
{
var match = m_textRegex.Match(text);
var groups = match.Groups;
var result = new Dictionary<string, string>(m_fields.Count);
for (int i = 0; i < m_fields.Count; i++)
result.Add(m_fields[i], groups[i + 1].Value);
return result;
}
}
You can parse the template using regular expressions. An expression like this will match each field definition and separator:
Match m = Regex.Match(template, #"^(\[%(?<name>.+?)%\](?<separator>.)?)+$")
The match will contain two named groups for (name and separator), each of which will contain a number of captures for each time they matched in the input string. In your example, the separator group would have one less capture than the name group.
You can then iterate over the captures, and use the results to extract the fields from the input string and store the values, like this:
if( m.Success )
{
Group name = m.Groups["name"];
Group separator = m.Groups["separator"];
int index = 0;
Dictionary<string, string> fields = new Dictionary<string, string>();
for( int x = 0; x < name.Captures.Count; ++x )
{
int separatorIndex = input.Length;
if( x < separator.Captures.Count )
separatorIndex = input.IndexOf(separator.Captures[x].Value, index);
fields.Add(name.Captures[x].Value, input.Substring(index, separatorIndex - index));
index = separatorIndex + 1;
}
// Do something with results.
}
Obviously in a real program you'd have to account for invalid input and such, which I didn't do here.
I would do this with a few lines of code. Loop through your template row, grabbing all text between "[" as the variable name and everything else as a terminator. Read all the text to the terminal, assign it to the variable name, repeat.
1- Use API for that sscanf(line, format, __arglist) check here
2- Use string split Like:
public IEnumerable<int> GetDataFromLines(string[] lines)
{
//handle the output data
List<int> data = new List<int>();
foreach (string line in lines)
{
string[] seperators = new string[] { "|", "\"" };
string[] results = line.Split(seperators, StringSplitOptions.RemoveEmptyEntries);
foreach (string result in results)
{
data.Add(int.Parse(result));
}
}
return data;
}
Test it with line:
line = "1234|1234567|123\"12345\"12\"123456";
string[] lines = new string[] { line };
GetDataFromLines(lines);
//output list items are:
1234
1234567
123
12345
12
123456
I have my file names with the name
PPD_EntryDetailRecord_07192010.txt
PPD_EntryDetailRecord_07182010.txt
PPD_EntryDetailRecord_07162010.txt
In that the data will be like
6111111111111111111111111111125000000001111111111111111111111111111111111111111 1
6111111111111111111111111111150000000001111111111111111111111111111111111111111 1
611111111111111111111111111116500000.721111111111111111111111111111111111111111 1
Now I would like to add all those which were in bold and should display the sum...
The best I can make of it:
int start = "61111111111111111111111111111".Length + 1;
int length = "2500000000".Length;
string[] lines = System.IO.File.ReadAllLines(filename);
foreach(string line in lines)
{
string data = line.SubString(start, length);
double number = double.parse(data, CultureInfo.InvariantCulture);
// sum it
}
If you are after the numbers in italic (not bold), and there are *s in the file, you can get the value like this (quick and dirty example code until you confirm the question):
string line = ""; // read a line from the file here
double lineValue = double.Parse(line.Split('*')[1]); // split by "*", get the second element, and parse as a double
You'd loop through all lines in the file and add lineValue to a sum variable.
Hope that helps.