I have a collection of strings that the user can add to or subtract from. I need a way to print the strings out in columns so that the 1st letter of each string aligned. However I the number of columns must be changeable during run time. Although the default is 4 columns the use can opt for any number from 1 to 6. I have no idea how to format an unknown quantity of string into an unknown number of columns.
Example Input:
it we so be a i o u t y z c yo bo go an
Example output of four columns
"Words" with 2 letters:
it so be we
yo bo go an
"Words" with 1 letter:
a i o u
t y z c
Note: not worried about parsing of the words I already have that in my code which I can add if helpful.
If you are trying to create fixed width columns, you can use string.PadLeft(paddingChar, width) and string.PadRight(paddingChar, width) when you are creating your rows.
http://msdn.microsoft.com/en-us/library/system.string.padleft.aspx
You can loop through your words and call .PadXXXX(width) on each word. It will automatically pad your words with the correct number of spaces to make your string the width you supplied.
You can divide the total line width by the number of columns and pad each string to that length. You may also want to trim extra long strings. Here's an example that pads strings that are shorter than the column width and trims strings that are longer. You may want to tweak the behavior for longer strings:
int Columns = 4;
int LineLength = 80;
public void WriteGroup(String[] group)
{
// determine the column width given the number of columns and the line width
int columnWidth = LineLength / Columns;
for (int i = 0; i < group.Length; i++)
{
if (i > 0 && i % Columns == 0)
{ // Finished a complete line; write a new-line to start on the next one
Console.WriteLine();
}
if (group[i].Length > columnWidth)
{ // This word is too long; truncate it to the column width
Console.WriteLine(group[i].Substring(0, columnWidth));
}
else
{ // Write out the word with spaces padding it to fill the column width
Console.Write(group[i].PadRight(columnWidth));
}
}
}
If you call the above method with this sample code:
var groupOfWords = new String[] { "alphabet", "alegator", "ant",
"ardvark", "ark", "all", "amp", "ally", "alley" };
WriteGroup(groupOfWords);
Then you should get output that looks like this:
alphabet alegator ant ardvark
ark all amp ally
alley
Related
In Our assignment we were given a task to create a new spreadsheet program with a 26 x 26 grid of textboxes without importing anything and make use of array (in my case I Used array of objects).
I created a 2 d array of objects containing size of grid (27x27). the reason of it being 27 instead of 26 is because the first row and column is to show the ABCDE etc and 12345 etc of the rows and columns.
now the rows indexation I had no problem because it is numeric. however, the letters I solved by creating a string array with alphabet from a to z and entering them through a for loop and it worked.
Now the next step is to be able to link the cells, however, I am a bit stumped, because people told me I have to use Ascii or smthin.
Can anyone help me plz on how to achieve the cell links?
I have been able to past the name of each cell using this code but I fear I just filled the .Text of the cells not the cells name per se:
for (int x = 1; x < TwoDArrayCells.GetLength(0); x++) //nested loop to create the grid of textboxes.
{
for (int y = 1; y < TwoDArrayCells.GetLength(1); y++)
{
Cells CellFields = new Cells(Name = $"{AlphabetRow[x]}{y}", x, y + 3); // called a new cell named CellFields.
CellFields.Text = Name;//Change to location if you wise to take
this.Controls.Add(CellFields);
}
}
The result I would like is to be able to after this be able to link cells. meaning if I insert in a text box A1 + A2 it knows that a1 is the first box in the first row of first column and the a2 is the box in the second row of the first column.
Assuming that Columns can be A-Z only (Capitals), You can extract the column index and row index as follows:
Given a cell, string cell = "A2";
- the column index: int column = cell[0] - 'A' + 1;
- the row index: int row = Convert.ToInt32(cell.Substring(1));
Explanation: for the column, take the first letter, subtract it from 'A' (the subtraction will be performed on the assci codes of the characters) and add 1 since your actual cells are stored starting from index 1. for the row, just parse the rest of the string to int.
I have a C# web form where a user inputs data about an excel file into a number of text boxes, including:
TXT_FirstDataRow - integer field which represents the first row that contains data
TXT_LastDataColumn - string field which represents the last column that contains data
TXT_Range - string field which contains the calculated data range using the above two fields
TXT_ColumnCount - The number of columns in the calculated range
I am currently using jQuery to automatically calculate the data range using the code below which works perfectly:
$('#TXT_FirstDataRow,#TXT_LastDataColumn').keyup(function () {
var row = $('#TXT_FirstDataRow').val();
var column = $('#TXT_LastDataColumn').val();
var range = 'A' + row + ':' + column; //All ranges start at column A
$('#TXT_Range').val(range);
});
I would now like to automatically populate the TXT_ColumnCount with the count of the columns. For example:
Range |Column Count
------+------------
A1:C |3
A7:BX |76
I imagine that this should be made easier as the ranges will always be starting from column A, so the column count should just be the equivalent column number of TXT_LastDataColumn, but I am afraid even this is beyond my slightly limited jQuery knowledge.
Any help would be greatly appreciated.
Thanks
I found an answer on SO that helped me, link below:
Convert excel column alphabet (e.g. AA) to number (e.g., 25)
function letterToNumbers(string) {
string = string.toUpperCase();
var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', sum = 0, i;
for (i = 0; i < string.length; i++) {
sum += Math.pow(letters.length, i) * (letters.indexOf(string.substr(((i + 1) * -1), 1)) + 1);
}
return sum;
}
If I have a table , with row with numbers like 70-0002098, lets just call the row, ID
I need the last 4 numbers for all the table rows,
So what I need is something like
foreach(var row in table)
{
var Id = row.ID(but just the last 4 digits)
}
Not sure what format you want to store it as, or what you want to do with it after, but...
Edit: Added an if check for length to avoid index out of bounds condition. Also corrected syntax- SubString() => Substring()
int count = 0;
foreach(var row in table){
string temp = row.ID.ToString();
count += (temp.Length > 5)? Convert.ToInt32(temp.Substring(temp.Length-5, 4)) : Convert.ToInt32(temp);
}
// But I have no idea what datatype you have for that or what
// you want to do (count up the integer values or store in an array or something.
// From here you can do whatever you want.
Your illustration suggests that the RowID is not currently a number (its got a hyphen in it) so I assume its a string
id.Right(4);
will return the right four characters. It doesn't guarantee they are numbers though. Right is an extension method of string which can be easily written, or copied from this thread Right Function in C#?
I'm going to parse a position base file from a legacy system. Each column in the file has a fixed column width and each row can maximum be 80 chars long. The problem is that you don't know how long a row is. Sometime they only have filled in the first five columns, and sometimes all columns are used.
If I KNOW that all 80 chars where used, then I simple could do like this:
^\s*
(?<a>\w{3})
(?<b>[ \d]{2})
(?<c>[ 0-9a-fA-F]{2})
(?<d>.{20})
...
But the problem with this is that if the last columns is missing, the row will not match. The last column can even be less number of chars then the maximum of that column.
See example
Text to match a b c d
"AQM45A3A text " => AQM 45 A3 "A text " //group d has 9 chars instead of 20
"AQM45F5" => AQM 45 F5 //group d is missing
"AQM4" => AQM 4 //group b has 1 char instead of 2
"AQM4 ASome Text" => AQM 4 A "Some Text" //group b and c only uses one char, but fill up the gap with space
"AQM4FSome Text" => No match, group b should have two numbers, but it is only one.
"COM*A comment" => Comments do not match (all comments are prefixed with COM*)
" " => Empty lines do not match
How should I design the Regular Expression to match this?
Edit 1
In this example, EACH row that I want to parse, is starting with AQM
Column a is always starting at position 0
Column b is always starting at position 3
Column c is always starting at position 5
Column d is always starting at position 7
If a column is not using all its space, is files up with spaces
Only the last column that is used can be trimed
Edit 2
To make it more clearer, I enclose here soem exemple of how the data might look like, and the definition of the columns (note that the examples I have mentioned earlier in the question was heavily simplified)
I'm not sure a regexp is the right thing to use here. If I understand your structure, you want something like
if (length >= 8)
d = everything 8th column on
remove field d
else
d = empty
if (length >= 6)
c = everything 6th column on
remove field c
else
c = empty
etc. Maybe a regexp can do it, but it will probably be rather contrived.
Try using a ? after the groups which could not be there. In this case if some group is missing you would have the match.
Edit n, after Sguazz answer
I would use
(?<a>AQM)(?<b>[ \d]{2})?(?<c>[ 0-9a-fA-F]{2})?(?<d>.{0,20})?
or even a + instead of the {0,20} for the last group, if could be that there are more than 20 chars.
Edit n+1,
Better like this?
(?<a>\w{3})(?<b>\d[ \d])(?<c>[0-9a-fA-F][ 0-9a-fA-F])(?<d>.+)
So, just to rephrase: in your example you have a sequence of character, and you know that the first 3 belong to group A, the following 2 belong to group B, then 2 to group C and 20 to group D, but there might not be this many elements.
Try with:
(?<a>\w{0,3})(?<b>[ \d]{0,2})(?<c>[ 0-9a-fA-F]{0,2})(?<d>.{0,20})
Basically these numbers are now an upper limit of the group as opposed to a fixed size.
EDIT, to reflect your last comment: if you know that all your relevant rows start with 'AQM', you can replace group A with (?<a>AQM)
ANOTHER EDIT: Let's try with this instead.
(?<a>AQM)(?<b>[ \d]{2}|[ \d]$)(?<c>[ 0-9a-fA-F]{0,2})(?<d>.{0,20})
Perhaps you could use a function like this one to break the string into its column values. It doesn't parse comment strings and is able to handle strings that are shorter than 80 characters. It doesn't validate the contents of the columns though. Maybe you can do that when you use the values.
/// <summary>
/// Break a data row into a collection of strings based on the expected column widths.
/// </summary>
/// <param name="input">The width delimited input data to break into sub strings.</param>
/// <returns>
/// An empty collection if the input string is empty or a comment.
/// A collection of the width delimited values contained in the input string otherwise.
/// </returns>
private static IEnumerable<string> ParseRow(string input) {
const string COMMENT_PREFIX = "COM*";
var columnWidths = new int[] { 3, 2, 2, 3, 6, 14, 2, 2, 3, 2, 2, 10, 7, 7, 2, 1, 1, 2, 7, 1, 1 };
int inputCursor = 0;
int columnIndex = 0;
var parsedValues = new List<string>();
if (String.IsNullOrEmpty(input) || input.StartsWith(COMMENT_PREFIX) || input.Trim().Length == 0) {
return parsedValues;
}
while (inputCursor < input.Length && columnIndex < columnWidths.Length) {
//Make sure the column width never exceeds the bounds of the input string. This can happen if the input string doesn't end on the edge of a column.
int columnWidth = Math.Min(columnWidths[columnIndex++], input.Length - inputCursor);
string columnValue = input.Substring(inputCursor, columnWidth);
parsedValues.Add(columnValue);
inputCursor += columnWidth;
}
return parsedValues;
}
sorry to be a pain but i'm having trouble formatting my list of strings into columns, in c#.
What i'm using is an input file such as;
"aa bbb cccc ddddd eeeeee fffffff"
and using a character limit ( word wrap) i need to space the words out like so
Output: Wrap = 20
aa bbb cccc
ddddd eeeeee fffffff
At the moment i can get the number of words per line, but for example if a word cannot fit because of the wrap, my program puts it onto another line, however i need to maintain the same number of strings per line so the first line would have 4 strings, but the rest have 5 because they have strings which are smaller.
Thanks in advance.
You could work out your spacing for each column by looping through every nth item in your array.
For example if you know the number of words per line, say it's 3 words per line, you can get every 3rd element, starting from your first element to get the first columns longest word.
so you'd have a for loop:
int longestWord = 0;
for(int i = 0; i < arrayLength; i += wordsPerLine)
{
if(array[i].Length > longestWord)
longestWord = array[i].Length;
}
Not sure how you'd implement this for every column but it's an idea?
The only way I can think of is complicated
you could first get the number of groups doing a split on the string and then get the number of chars in each group.
When you have that, you can start making groups, and you stop when one of the subgroups exceeds the limit
//creates groups and lengths arrays
string letters = aaa bbbb ccc dd eeeeeee ffffffffff gggggggggggggggg hh iiiiiiiiii;
string[] groups = letters.split(" ");
int[] lengths = new int[groups.length]
for(int i = 0; i<groups.length, i++){
lengths[i] = groups[i].length;
}
int numberofrows;
//starts doing groups: is one element is more that 20, then if 2 elements are more
//than 20, 3 elements more than 20....
// when a sum is more than 20, then the last amount of groups was the one to use
for(int i = 0, i<groups.length<i++){
for(int j = 1, j<=groups.length, j++)
int sum = add(i, j)
if(sum > limit){
numberofrows = j-1;
return;
}
}
}
//this makes the addition of several elements of the array, next to the other
public int add(int index, id sums){
int sum = lengths[index];
for(int i = 0, i<=sums;i++){
sum += lengths[index+i];
}
return sum;
}