TEXTFILE I/O : Don't write same things - unity3d

I have a function that stores the coordinates and the name of that chunk, but the problem is that this function gets called everytime new chunks get generated, but the old ones keep being loaded if they are not far. So the result is that in the textfile, the function writes the chunks sometimes 2 times.
I don't want this to happen and have the function only write every chunk once.
The main problem is that I can't use StreamwWriter and StreamReader at the same time.
This is my code:
function saveLoadedChunk() {
var loadedChunks : GameObject[] = FindObjectsOfType(GameObject) as GameObject[];
var fileName = "C:/Reactor Games/chunks.txt";
var sw : System.IO.StreamWriter = new System.IO.StreamWriter(fileName, true);
for (var i = 0; i < loadedChunks.length ; i++) {
if(loadedChunks[i].name.Substring(0,5) == "Chunk" || loadedChunks[i].name.Substring(0,5) == "_TERR") {
if(loadedChunks[i].tag != "Player") {
var xco = loadedChunks[i].transform.position.x;
var yco = loadedChunks[i].transform.position.y;
var zco = loadedChunks[i].transform.position.z;
var stringToWrite = "Chunk (" + xco + ", " + yco + ", " + zco + ")";
sw.WriteLine(stringToWrite);
}
}
}
sw.Flush();
sw.Close();
}

Preamble
I mostly work with C#, so there could be some mistakes in syntax.
Solution
You can store all your chunks in memory set. Inside saveLoadedChunk you are going to update this set and then write it's contents to file:
var chunks: HashSet<Vector3> = new HashSet<Vector3>();
function saveLoadedChunk() {
var loadedChunks : GameObject[] = FindObjectsOfType(GameObject) as GameObject[];
for (var i = 0; i < loadedChunks.length ; i++)
if(loadedChunks[i].name.Substring(0,5) == "Chunk" || loadedChunks[i].name.Substring(0,5) == "_TERR")
if(loadedChunks[i].tag != "Player")
chunks.Add(loadedChunks[i].transform.position);
var fileName = "C:/Reactor Games/chunks.txt";
var sw : System.IO.StreamWriter = new System.IO.StreamWriter(fileName, false);
for (var chunk: Vector3 in chunks) {
var stringToWrite = "Chunk (" + chunk.x + ", " + chunk.y + ", " + chunk.z + ")";
sw.WriteLine(stringToWrite);
}
}
The drawback here is:
That you start with blank chunks set every time app is launched.
You store all the chunks' coords in memory. But I wouldn't say that this is drawback until you have really-really lot of chunks.
In order to solve first problem you need to fill chunks with corrds stored in C:/Reactor Games/chunks.txt once the app is started.

Related

EA - Table template for single element manipulation

I'm trying to design a template that generates a document based on the following Diagram.
For each System (1 or 2) there is a Chapter, which will be further populated with subchapters for every "Element type C".
Example of chapter structure
The template I'm using is this one:
And it calls a table:
While scripting the fragment of this, for each element type C, I'm checking the connection type ( connection Y) to see if the element is related and can be added to the bottom half of the table. If so, the ID of element Type B is added to an XML structure.
The code I'm using is the following:
function arrange_data_in_xml(objectid) {
//Get the repository type
var repotype = Repository.RepositoryType();
//Create the xml structure
var xmlDOM = new COMObject("MSXML2.DOMDocument.6.0");
xmlDOM.validateOnParse = false;
xmlDOM.async = false;
var node = xmlDOM.createProcessingInstruction("xml", "version='1.0' encoding='ISO-8859-1'");
xmlDOM.appendChild(node);
var xmlRoot = xmlDOM.createElement("EADATA");
xmlDOM.appendChild(xmlRoot);
var xmlDataSet = xmlDOM.createElement("Dataset_0");
xmlRoot.appendChild(xmlDataSet);
var xmlData = xmlDOM.createElement("Data");
xmlDataSet.appendChild(xmlData);
var part1A = Repository.GetElementSet(sqlquery, 2);
//Session.Output(part1A.Count)
//This cycle will iterate over each Element Type B
for (var i = 0; i < part1A.Count; i++) {
var ElementTypeBrow = ""
var countElementTypeB = 0;
Session.Output("DEBUG 0 " + part1A.GetAt(i).ElementID + " -- " + part1A.GetAt(i).Name + " -- " + objectid)
var xmlRow = xmlDOM.createElement("Row");
xmlData.appendChild(xmlRow);
var xmlName = xmlDOM.createElement("Object_ID");
xmlName.text = part1A.GetAt(i).ElementID;
xmlRow.appendChild(xmlName);
var xmlName = xmlDOM.createElement("ElementTypeCName");
xmlName.text = part1A.GetAt(i).Name;
xmlRow.appendChild(xmlName);
for (var k = 0; k < part1A.GetAt(i).TaggedValues.Count; k++) {
var tv = part1A.GetAt(i).TaggedValues.GetAt(k);
if (tv.Name == 'Proprety X') {
var xmlName = xmlDOM.createElement("ElementTypeC.TagValue1");
xmlName.text = tv.Value;
xmlRow.appendChild(xmlName);
} else if (tv.Name == 'Proprety Y') {
var xmlName = xmlDOM.createElement("ElementTypeC.TagValue2");
xmlName.text = tv.Value;
xmlRow.appendChild(xmlName);
}
}
for (var j = 0; j < part1A.GetAt(i).Connectors.Count; j++) {
var connector = part1A.GetAt(i).Connectors.GetAt(j);
if (connector.Stereotype == 'Connection type Z') {
var xmlName = xmlDOM.createElement("ElementTypeC.TagValue3");
xmlName.text = Repository.GetElementByID(connector.SupplierID).Name;
xmlRow.appendChild(xmlName);
} else if (connector.Stereotype == 'Connection type Y') {
var xmlName = xmlDOM.createElement("ElementTypeC.TagValue4");
xmlName.text = Repository.GetElementByID(connector.ClientID).Name;
xmlRow.appendChild(xmlName);
} else if (connector.Stereotype == 'Connection type X'') {
var ElementTypeB = Repository.GetElementByID(connector.SupplierID)
//Check if the ElementTypeB is connected to the current interface
if (check_interface(ElementTypeB.ElementID) == objectid) {
//Session.Output("DEBUG 1 " + part1A.GetAt(i).Name + " - " + ElementTypeB.Name)
var ElementTypeBalias = ""
if (ElementTypeB.Alias != "") {ElementTypeBalias = " (" + ElementTypeB.Alias + ")"}
ElementTypeBrow = ElementTypeB.Name + ElementTypeBalias + " \n" + ElementTypeBrow
countElementTypeB = countElementTypeB + 1
}
}
}
//Session.Output("DEBUG 1 " +ElementTypeBrow + " - " + countElementTypeBs + " - " + ElementTypeB.Name)
var xmlName = xmlDOM.createElement("ApplicableElementTypeB-Hyperlink");
if (countElementTypeBs > 1) {
xmlName.text = ElementTypeBrow.trimStart();
} else {
xmlName.text = ElementTypeB.ElementGUID+ElementTypeBrow;
}
xmlRow.appendChild(xmlName);
}
return xmlDOM.xml;
}
The problem that I'm having now is the result list of elements is taken as one, ie all of the elements of the bottom half of the table are as one.
Is there a way to manipulate each element individually (for example create a hyperlink for each entry)?
I've tried to rearrange the XML stucture. But the problem remains.
Fragments like this expect there contents in the form of a table, with rows and columns.
Currently you are only returning a single row, but somehow you would like to split the different values for ElementTypeBName-Hyperlink into different rows.
I think you have two possibilities here:
Return each ElementTypeBName-Hyperlink element with a different name e.g. ElementTypeBName-Hyperlink1, ElementTypeBName-Hyperlink2,... and then use each of those in your table template.
Downside of this approach is that it isn't flexible at all, and only useful if you have more or less the same number of ElementB names.
Split your template into two templates. One template for the upper part, and one for the lower part.
Another observation is that you are taking the complicated (and slow) route. For requirements like this, it's much easier to create an SQL template instead of a script template.

Aspose Worksheet not parsing decimal numbers correctly on German server; ignoring period delimiter (123.45 -> 12345)

I have an import task that parses a huge .dat file as an Aspose Workbook.
This was the original code:
public static List<QueryResult> GetAsposeExcelDocumentWithSheetIndex(string filename, string propertyNames, int sheetIndex = 0, int skipRows = 0, int columnToScanForValidEntries = 0, Stream stream = null)
{
Sitecore.Diagnostics.Log.Info("Begin GetAsposeExcelDocumentWithSheetIndex: Filename: " + filename, typeof(UploadHelper));
var loadOptions = new Aspose.Cells.LoadOptions(LoadFormat.Excel97To2003);
if (filename.EndsWith(".xlsx"))
{
loadOptions = new Aspose.Cells.LoadOptions(LoadFormat.Xlsx);
}
else if (filename.EndsWith(".dat") || filename.EndsWith(".csv"))
{
loadOptions = new Aspose.Cells.LoadOptions(LoadFormat.CSV);
}
//var fsStats = new StreamWriter(HttpContext.Current.Server.MapPath("/_uploads/ftp/import.txt"), false);
//fsStats.WriteLine(DateTime.Now.ToString("h:mm:ss") + " - Opening file: " + filename);
//fsStats.Flush();
loadOptions.ParsingFormulaOnOpen = false;
try
{
var workbook = stream != null ? new Workbook(stream: stream, loadOptions: loadOptions) : new Aspose.Cells.Workbook(filename, loadOptions);
Worksheet worksheet = workbook.Worksheets[sheetIndex];
//fsStats.WriteLine(DateTime.Now.ToString("h:mm:ss") + " - Opened sheet");
//fsStats.Flush();
var list = new List<QueryResult>();
for (int i = skipRows, loopTo = worksheet.Cells.Rows.Count + skipRows - 1; i <= loopTo; i++)
{
//fsStats.WriteLine(DateTime.Now.ToString("h:mm:ss") + " - Reading row: " + i);
//fsStats.Flush();
if (worksheet.Cells.GetCell(i, columnToScanForValidEntries) != null &&
worksheet.Cells.GetCell(i, columnToScanForValidEntries).Value != null)
{
NumberFormatInfo nfi = new CultureInfo("en-US", false).NumberFormat;
var obj = new QueryResult();
var propNames = propertyNames.Split(',');
for (int j = 0, loopTo1 = propNames.Length - 1; j <= loopTo1; j++)
{
Cell cellInfo = worksheet.Cells.GetCell(i, j);
if (cellInfo != null)
{
// specific excluded properties
var propName = propNames[j];
var parseAsString = PropNameShouldNeverBeParsedAsDate(propName);
if ((cellInfo.Type == CellValueType.IsDateTime) && !parseAsString && cellInfo.DateTimeValue.Year > 2010 && !cellInfo.Name.StartsWith("X") && !cellInfo.Name.StartsWith("Y") && !cellInfo.Name.StartsWith("AC")) // this second check is bc some dates weren't return as a DateTime type in the Iplot file
{
// Colmun X and Y should NEVER be a date time
obj.Properties.Add(propNames[j], cellInfo.DateTimeValue);
}
else
{
obj.Properties.Add(propNames[j], cellInfo.StringValue);
}
}
else
{
obj.Properties.Add(propNames[j], null);
}
}
list.Add(obj);
}
}
//fsStats.WriteLine(DateTime.Now.ToString("h:mm:ss") + " - Done reading");
//fsStats.Flush();
//fsStats.Close();
return list;
}
catch (Exception ex)
{
Sitecore.Diagnostics.Error.LogError("Error GetAsposeExcelDocumentWithSheetIndex:" + ex.ToString() + ex.StackTrace);
//fsStats.WriteLine(DateTime.Now.ToString("h:mm:ss") + " - Error: " + ex.ToString());
//fsStats.Flush();
//fsStats.Close();
}
return null;
}
This worked as expected on my local, however the production website is hosted in Germany. The code runs correctly when manually triggered from the admin page (which requires being logged into Sitecore), but when run automatically as a scheduled task, it fails because it's not parsing numbers correctly
public static List<QueryResult> GetAsposeExcelDocumentWithSheetIndex(string filename, string propertyNames, int sheetIndex = 0, int skipRows = 0, int columnToScanForValidEntries = 0, Stream stream = null)
{
//var fsStats = new StreamWriter(HttpContext.Current.Server.MapPath("/_uploads/ftp/import.txt"), false);
//fsStats.WriteLine(DateTime.Now.ToString("h:mm:ss") + " - Opening file: " + filename);
//fsStats.Flush();
loadOptions.ParsingFormulaOnOpen = false;
try
{
var workbook = stream != null ? new Workbook(stream: stream, loadOptions: loadOptions) : new Aspose.Cells.Workbook(filename, loadOptions);
Worksheet worksheet = workbook.Worksheets[sheetIndex];
//fsStats.WriteLine(DateTime.Now.ToString("h:mm:ss") + " - Opened sheet");
//fsStats.Flush();
var list = new List<QueryResult>();
for (int i = skipRows, loopTo = worksheet.Cells.Rows.Count + skipRows - 1; i <= loopTo; i++)
{
//fsStats.WriteLine(DateTime.Now.ToString("h:mm:ss") + " - Reading row: " + i);
//fsStats.Flush();
if (worksheet.Cells.GetCell(i, columnToScanForValidEntries) != null &&
worksheet.Cells.GetCell(i, columnToScanForValidEntries).Value != null)
{
NumberFormatInfo nfi = new CultureInfo("en-US", false).NumberFormat;
var obj = new QueryResult();
var propNames = propertyNames.Split(',');
for (int j = 0, loopTo1 = propNames.Length - 1; j <= loopTo1; j++)
{
Cell cellInfo = worksheet.Cells.GetCell(i, j);
if (cellInfo != null)
{
// specific excluded properties
var propName = propNames[j];
var parseAsString = PropNameShouldNeverBeParsedAsDate(propName);
if ((cellInfo.Type == CellValueType.IsDateTime) && !parseAsString && cellInfo.DateTimeValue.Year > 2010 && !cellInfo.Name.StartsWith("X") && !cellInfo.Name.StartsWith("Y") && !cellInfo.Name.StartsWith("AC")) // this second check is bc some dates weren't return as a DateTime type in the Iplot file
{
// Colmun X and Y should NEVER be a date time
obj.Properties.Add(propNames[j], cellInfo.DateTimeValue);
}
else
{
var value = cellInfo.StringValue;
if (cellInfo.Type == CellValueType.IsNumeric || propName.Contains("NUM_VALUE"))
{
try
{
if (cellInfo.StringValue == "2.074.927" || cellInfo.DoubleValue == 2074927 || cellInfo.DoubleValue == 2074.927)
{
Sitecore.Diagnostics.Log.Info("Value: " + cellInfo.Value.ToString() + " StringValue: " + cellInfo.StringValue + " DoubleValue: " + cellInfo.DoubleValue.ToString(nfi), typeof(UploadHelper));
Sitecore.Diagnostics.Log.Info("Convert.ToDouble Value: " + Convert.ToDouble(cellInfo.Value) + ", " + Convert.ToDouble(cellInfo.Value).ToString(nfi), typeof(UploadHelper));
Sitecore.Diagnostics.Log.Info("DoubleValue: " + (cellInfo.DoubleValue) + ", " + (cellInfo.DoubleValue).ToString(nfi), typeof(UploadHelper));
Sitecore.Diagnostics.Log.Info("StringValue: " + (cellInfo.StringValue), typeof(UploadHelper));
Sitecore.Diagnostics.Log.Info("FloatValue: " + (cellInfo.FloatValue) + ", " + (cellInfo.FloatValue).ToString(nfi), typeof(UploadHelper));
Sitecore.Diagnostics.Log.Info("StringValueWithoutFormat: " + (cellInfo.StringValueWithoutFormat), typeof(UploadHelper));
Sitecore.Diagnostics.Log.Info("IntValue: " + (cellInfo.IntValue), typeof(UploadHelper));
}
if (Convert.ToDouble(cellInfo.Value).ToString() != value)
{
Double val;
if (Double.TryParse(value, System.Globalization.NumberStyles.Any, nfi, out val))
{
Sitecore.Diagnostics.Log.Info("Using value " + val, typeof(UploadHelper));
obj.Properties.Add(propNames[j], val);
}
else
{
Sitecore.Diagnostics.Log.Info("Failed to parse as decimal, using stringValue " + value, typeof(UploadHelper));
obj.Properties.Add(propNames[j], value);
}
}
else
{
Sitecore.Diagnostics.Log.Info("Value as double matches StringValue", typeof(UploadHelper));
obj.Properties.Add(propNames[j], Convert.ToDouble(cellInfo.Value));
}
}catch(Exception ex)
{
Sitecore.Diagnostics.Log.Info(ex.Message, typeof(UploadHelper));
obj.Properties.Add(propNames[j], cellInfo.StringValue);
}
}
else
{
obj.Properties.Add(propNames[j], cellInfo.StringValue);
}
}
}
else
{
obj.Properties.Add(propNames[j], null);
}
}
list.Add(obj);
}
}
The reason why I added all the additional code for numeric values is because on the German server, cellInfo.StringValue returns an improperly formatted number as a string - it uses periods instead of commas, so large decimal values end up being returned like 12.703.1005 instead of 12,703.1005.
So, I tried to return cellInfo.DoubleValue instead when the cell is numeric, but that ALSO returns wrong. Some decimals like 12.7 are being interpreted as dates, so cellInfo.DoubleValue is entirely wrong, but cellInfo.StringValue gives me the correct number (as a string). But the one thing that's still not working either as strings or decimals is large numbers that have a comma and a decimal.
In the second block of code you can see all the logging I added in. Here is the output on my local, for parsing a value of 2074.927
27908 10:47:59 INFO Value: 2074.927 StringValue: 2074.927 DoubleValue: 2074.927
27908 10:48:02 INFO Convert.ToDouble Value: 2074.927, 2074.927
27908 10:48:04 INFO DoubleValue: 2074.927, 2074.927
27908 10:48:07 INFO StringValue: 2074.927
27908 10:48:10 INFO FloatValue: 2074.927, 2074.927
27908 10:48:21 INFO StringValueWithoutFormat: 2074.9270000000001
27908 10:48:24 INFO IntValue: 2074
and here is the output on the German server:
ManagedPoolThread #12 15:36:04 INFO Value: 2074927 StringValue: 2.074.927 DoubleValue: 2074927
ManagedPoolThread #12 15:36:04 INFO Convert.ToDouble Value: 2074927, 2074927
ManagedPoolThread #12 15:36:04 INFO DoubleValue: 2074927, 2074927
ManagedPoolThread #12 15:36:04 INFO StringValue: 2.074.927
ManagedPoolThread #12 15:36:04 INFO FloatValue: 2074927, 2074927
ManagedPoolThread #12 15:36:04 INFO StringValueWithoutFormat: 2074927
ManagedPoolThread #12 15:36:04 INFO IntValue: 2074927
On the German server, I don't have a single instance of the correct number. It early strips the decimal place (returning the number several orders of magnitude larger than it should be), or it gives me a string value that has a period instead of a comma, which I cannot parse as a decimal.
Why is the German server messing this up? How can I change my code to parse correctly on the German server? As you can see in the code I'm already trying to use NumberFormatInfo to give me the correct delimiters but it doesn't matter since the DoubleValue is returning with no delimeter to begin with.
#Anshul Samaiyar,
If you could specify your custom formatting, i.e., "## ###.##%" for the given value to the cell in MS Excel manually, you will also get this result ("1231123.%"). So, Aspose.Cells works the same way as MS Excel does. Your custom formatting is not right. Please see the following sample code with (updated) custom formatting and give it a try, it will give you expected results.
e.g.
Sample code:
//Create a new (empty) workbook
Workbook workbook = new Workbook();
//Get the first (default) worksheet
Worksheet worksheet = workbook.getWorksheets().get(0);
//Get A1 cell
Cell cell = worksheet.getCells().get("A1");
//Specify double value
Double dataValue = 12311.23;
dataValue = Double.parseDouble(dataValue.toString());
cell.putValue(dataValue);
//Create a style and set the custom formattings
Style cellStyle = workbook.createStyle();
cellStyle.setCustom("## ###.##\\%");
//Apply the style to the cell
cell.setStyle(cellStyle);
//Autofit column to show all values
worksheet.autoFitColumn(0);
//Save the Excel file
workbook.save("f:\\files\\out1.xlsx");
//Save to PDF file
workbook.save("f:\\files\\out12.pdf");
Hope this helps, you may also post queries in the dedicated forums.
Facing similar issue where
dataValue = 12311.23;
dataValue = Double.parseDouble(dataValue.toString());
cellStyle.setCustom("## ###.##%");
is not getting change to 12 311.23 but getting g converted to 1231123.% any solution for the issue is welcome.

Invalid IL code error in Unity3D

I'm trying to use perlin noise to generate terain using Unity3D (version 5.0.2f1) but I get this error:
InvalidProgramException: Invalid IL code in TerrainGenerator:GenerateFloor (): IL_0045: call 0x0a00000c
TerrainGenerator.Generate () (at Assets/TerrainGenerator.js:36)
TerrainGenerator.Start () (at Assets/TerrainGenerator.js:23)
Code:
function GenerateFloor(){
print("The function was called");
if(!(seed > 0)){
Debug.LogError("Seed not valid. Seed: " + seed + " .");
seed = Random.Range(0, 1000000000000000);
Debug.LogError("Generated new seed. Seed: " + seed + ".");
}
for(var i = 0; i < heightMap.length; i++){
if(currentX == Math.Sqrt(size)){
currentX = 0;
currentZ++;
}
else if(currentX > Math.Sqrt(size)) Debug.LogError("How did this happen?! currentX = " + currentX + " size = " + size + " .");
var height = Mathf.PerlinNoise(currentX, currentZ);
heightMap[currentX * currentZ] = new Vector3(currentX, height, currentZ);
print("For loop worked");
//yield;
}
}
Your param 1000000000000000 in Random.Range is excessively beyond maximum. Maybe you want int.MaxValue ? which would be 2147483647
Interesting it caused such a compiler error with IL2CPP !

GAS importHtml not updating or emailing correctly when spreadsheet not active using time trigger

I am using an importHtml command to bring in barometric pressure data to a spreadsheet. Then, I have it email me if the barometric pressure gets higher or lower than a certain values. This works great when I run the script with everything open. However, I've tried having a time trigger check it every four hours, but then the variables don't seem to grab the right info.
An email when it works right says, "This is just a test. The loop variable ended as 1 and the current pressure is 29.73".
An email when it doesn't work right says, "This is just a test. The loop variable ended as 16 and the current pressure is #N/A".
Here is the code:
function checkPressure() {
// Get the data from the "Chart Data" sheet.
var ss = SpreadsheetApp.openById("0Ah2VsNnRu1aWdEFkWGtTQklqTTd6bVY4UW8yQ1F3TWc");
var sheet = ss.getSheetByName("Chart Data");
var dataRange = sheet.getRange(2,1,16,4);
var dataBp = dataRange.getValues();
Browser.msgBox(dataBp);
// Initialize variables/constants
var highPressure = false;
var lowPressure = false;
var highBpLimit = 30.01;
var lowBpLimit = 29.99;
var i = 0;
var headers = ("Date", "Time", "Date/Time", "Pressure");
var myEmail = "MYEMAILHERE";
while (!highPressure && !lowPressure && i < dataBp.length) {
if (dataBp[i][3] > highBpLimit) {
highPressure = true;
var highBpReading = dataBp[i][3];
var highBpDate = dataBp[i][0];
var highBpTime = dataBp[i][1];
}
if (dataBp[i][3] < lowBpLimit) {
lowPressure = true;
var lowBpReading = dataBp[i][3];
var lowBpDate = dataBp[i][0];
var lowBpTime = dataBp[i][1];
}
i++;
}
if (highPressure) {
var message = "There is a barometric pressure of " + highBpReading + " at " + highBpTime + " on the date of " + highBpDate;
MailApp.sendEmail(myEmail, "High BP Warning", message);
}
if (lowPressure) {
var message = "There is a barometric pressure of " + lowBpReading + " at " + lowBpTime + " on the date of " + lowBpDate;
MailApp.sendEmail(myEmail, "Low BP Warning", message);
}
MailApp.sendEmail(myEmail,"Test BP Warning", "This is just a test. The loop variable ended as " + i + " and the current pressure is " + dataBp[0][3]);
}

C sharp delimiter

In a given sentence i want to split into 10 character string. The last word should not be incomplete in the string. Splitting should be done based on space or , or .
For example:
this is ram.he works at mcity.
now the substring of 10 chars is,
this is ra.
but the output should be,
this is.
Last word should not be incomplete
You can use a regular expression that checks that the character after the match is not a word character:
string input = "this is ram.he";
Match match = Regex.Match(input, #"^.{0,10}(?!\w)");
string result;
if (match.Success)
{
result = match.Value;
}
else
{
result = string.Empty;
}
Result:
this is
An alternative approach is to build the string up token by token until adding another token would exceed the character limit:
StringBuilder sb = new StringBuilder();
foreach (Match match in Regex.Matches(input, #"\w+|\W+"))
{
if (sb.Length + match.Value.Length > 10) { break; }
sb.Append(match.Value);
}
string result = sb.ToString();
Not sure if this is the sort of thing you were looking for. Note that this could be done a lot cleaner, but should get you started ... (may want to use StringBuilder instead of String).
char[] delimiterChars = { ',', '.',' ' };
string s = "this is ram.he works at mcity.";
string step1 = s.Substring(0, 10); // Get first 10 chars
string[] step2a = step1.Split(delimiterChars); // Get words
string[] step2b = s.Split(delimiterChars); // Get words
string sFinal = "";
for (int i = 0; i < step2a.Count()-1; i++) // copy count-1 words
{
if (i == 0)
{
sFinal = step2a[i];
}
else
{
sFinal = sFinal + " " + step2a[i];
}
}
// Check if last word is a complete word.
if (step2a[step2a.Count() - 1] == step2b[step2a.Count() - 1])
{
sFinal = sFinal + " " + step2b[step2a.Count() - 1] + ".";
}
else
{
sFinal = sFinal + ".";
}