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.
Related
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 split the input paragraph by . and store it in an array like this:
string[] totalSentences = inputPara.Split('.')
then the function below is called which calculates total number of Words from each sentence like this:
public void initParaMatrix()
{
int size = 0;
for (int i = 0; i < totalSentences.Length; i++)
{
string[] words = totalSentences[i].Split();
size = size + words.Length;
//rest of the logic here...
}
matrixSize = size;
paraMatrix = new string[matrixSize, matrixSize];
}
paraMatrix is a 2D matrix equal to length of all words which I need to make in my logic.
The problem here is when I input only one sentence which has 5 words, the size variable gets the value 7. I tried the debugger and I was getting total of 2 sentences instead of 1.
Sentence 1. "Our present ideas about motion." > this is actual sentence which have only 5 words
Sentence 2. " " > this is the exact second sentence I'm getting.
Here is the screenshot:
Why I'm getting two sentences here and how is size getting value 7?
This makes perfect sense. If the second sentence has nothing but a " ", and you split along the " ", then you'll have two empty strings as a result. The easiest thing to do here is change the line you do the split, and add a trim:
string[] words = totalSentences[i].Trim().Split();
I don't know what version of Split that you're using since it accepts no parameters, but if you use String.Split you can set the second parameter so that empty entries are automatically removed by using the option StringSplitOptions.RemoveEmptyEntries.
You're not resetting the size integer to zero. So that's why you get 7 for the second sentence.
For the second sentence, which is a space, try inputPara.Trim() which should remove the space at the end of the string.
I have a problem that I busted my head for 7 days, so I decide to ask you for help. Here is my problem:
I read data from datagridview (only 2 cell), and fill all given data in stringbuilder, its actually article and price like invoice (bill). Now I add all what I get in stringbuilder in just string with intention to split string line under line, and that part of my code work but not as I wont. Article is one below another but price is one price more left another more right not all in one vertical line, something like this:
Bread 10$
Egg 4$
Milk 5$
My code:
string[] lines;
StringBuilder sbd = new StringBuilder();
foreach (DataGridViewRow rowe in dataGridView2.Rows)
{
sbd.Append(rowe.Cells[0].Value).Append(rowe.Cells[10].Value);
sbd.Append("\n");
}
sbd.Remove(sbd.Length - 1, 1);
string userOutput = sbd.ToString();
lines = userOutput.Split(new string[] { "\r", "\n" },
StringSplitOptions.RemoveEmptyEntries);
You can use the Trim method in order to remove existing leading and trailing spaces. With PadRight you can automatically add the right number of spaces in order to get a specified total length.
Also use a List<string> that grows automatically instead of using an array that you get from splitting what you just put together before:
List<string> lines = new List<string>();
foreach (DataGridViewRow row in dataGridView2.Rows) {
lines.Add( row.Cells[0].Value.ToString().Trim().PadRight(25) +
row.Cells[10].Value.ToString().Trim());
}
But keep in mind that this way of formatting works only if you display the string in a monospaced font (like Courier New or Consolas). Proportional fonts like Arial will yield jagged columns.
Alternatively you can create an array with the right size by reading the number of lines from the Count property
string[] lines = new string[dataGridView2.Rows.Count];
for (int i = 0; i < lines.Length; i++) {
DataGridViewRow row = dataGridView2.Rows[i];
lines[i] = row.Cells[0].Value.ToString().Trim().PadRight(25) +
row.Cells[10].Value.ToString().Trim();
}
You can also use the PadLeft method in order to right align the amounts
row.Cells[10].Value.ToString().Trim().PadLeft(10)
Have you tried this String Split method ?
String myString = "Bread ;10$;";
String articleName = myString.split(';')[0];
String price = myString.split(';')[1];
This question started out with someone wanting to import every apparent 'line of text' in a Word document into a row in an Excel sheet, but I'm sure this is not possible without some development.
I would like to insert a newline (whatever that may be configured as) at every point that a string is wrapped to a new line when displayed in a window. How can I do that? I figure I would need to query the window and get an array of its text lines, then count characters in each line, and in the original string, insert a newline after the number of characters that are displayed for that line.
I do of course realise that changing the window size will invalidate all the work of this code I'm asking how to write, but that is not a relevant issue here.
USEFUL INFO:
I have found a solution to the original, Word to Excel export, problem. When you save a Word document as a text file, after you click Save on the Save dialogue, you are given another dialogue with an option for inserting line breaks.
What you can do is something like this:
int width = txtBox.width;
Graphics g = CreateGraphics();
SizeF size = g.MeasureString(myText, txtBox.Font);
if (size.Width > width)
{
int i = 0;
List<string> lines = new List<String>();
string str = "";
while (i<myText.Length)
{
str = str + myText.SubString(i,1);
int w = (int)(g.MeasureString(str, txtBox.Font).Width);
while (w<width && i<myText.Length)
{
i++;
str = str + myText.SubString(i,1);
}
str = str + '\n';
}
// str now contains your newline formatted string
return str;
}
return myText;
What you can do is get the width of the display control and the font it is using, then use GetTextMetrics to get a TEXTMETRIC struct that can be used to find out the width of each character. This is very involved as it takes into account all the different character profiles.
An easier way is to use GetTextExtentPoint32 which, given a string and the font properties, will return its width in pixels. So you can make a rough estimate as to where the line break would be, call this function on that substring, and insert a line break when the result of GetTextExtentPoint32 is just less than the width of the text control.
Cheers.
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.