Wrap string without cutting words for thermal printer - c#

I am trying to print a string by thermal printer, but the problem is that paper accept only 32 charcters in a line and than break rest text to another line, by this last character always cut into two parts and string is hard to understand.
Example:
string PrintStr = "01-(200),02-(200),03-(200),04-(200),05-(200)";
Current output:
01-(200),02-(200),03-(200),04-(20 # <- 200 is broken into 20 and 0
0),05-(200)
Better output:
01-(200),02-(200),03-(200), # Split on comma, numbers are preserved
04-(200),05-(200)
I also use a Linq mehtod to break line after 32th character but the last character is cutting. I just want after last Comma "," in first 32 characters a new line will be add by that my string will break in readable text. I am sharing my code. Thanks in advance for help..
Input:
var PrintStr = "01-(200),02-(200),03-(200),04-(200),05-(200),06-(200),07-(200),08-(200),09-
(200),10-(200),11-(200),12-(200),13-(200),14-(200),15-
(200),16-(200),17-(200),18-(200),19-(200),20-(200),21-(200),22-(200),23-(200),24-(200),25-(200),26-
(200),27-(200),28-(200),29-(200),30-(200),31-(
200),32-(200),33-(200),34-(200),35-(200),36-(200),37-(200),38-(200),39-(200),40-(200),41-(200),42-
(200),43-(200),44-(200),45-(200),46-(200),47-(200),48-
(200),49-(200),50-(200),51-(200),52-(200),53-(200),54-(200),55-(200),56-(200),57-(200),58-(200),59-
(200),60-(200),61-(200),62-(200),63-(200),64-
(200),65-(200),66-(200),67-(200),A1111-(200)"
Code (my attept):
var AdjustPrintStr = string.Join(Environment.NewLine, PrintStr
.ToLookup(c => k++ / 32)
.Select(e => new String(e.ToArray())));
Output (current, unwanted):
01-(200),02-(200
),03-(200),04-(200),05-(200),06-
(200),07-(200),08-(200),09-(200)
,10-(200),11-(200),12-(200),13-(
200),14-(200),15-(200),16-(200),
17-(200),18-(200),19-(200),20-(2
00),21-(200),22-(200),23-(200),2
4-(200),25-(200),26-(200),27-(20
0),28-(200),29-(200),30-(200),31
-(200),32-(200),33-(200),34-(200
),35-(200),36-(200),37-(200),38-
(200),39-(200),40-(200),41-(200)
,42-(200),43-(200),44-(200),45-(
200),46-(200),47-(200),48-(200),
49-(200),50-(200),51-(200),52-(2
00),53-(200),54-(200),55-(200),5
6-(200),57-(200),58-(200),59-(20
0),60-(200),61-(200),62-(200),63
-(200),64-(200),65-(200),66-(200
Note, that the last "),A1111-(200)" fragment is lost

Well, you have to implement such a routine
(split text at at characters ensuring at most maxWidth characters in each line) manually;
it's not that difficult:
public static IEnumerable<string> MySplit(string text,
int maxWidth, params char[] at) {
if (null == text)
throw new ArgumentNullException(nameof(text));
else if (maxWidth <= 0)
throw new ArgumentOutOfRangeException(nameof(maxWidth));
else if (null == at)
throw new ArgumentNullException(nameof(at));
int startIndex = 0;
int bestIndex = -1;
for (int i = 0; i < text.Length; ++ i) {
if ((i - startIndex) > maxWidth) {
if (bestIndex < 0)
bestIndex = i - 1;
yield return text.Substring(startIndex, bestIndex - startIndex + 1);
startIndex = bestIndex += 1;
bestIndex = -1;
}
if (at.Contains(text[i]))
bestIndex = i;
}
yield return text.Substring(startIndex);
}
Now, let's print out the source string:
string PrintStr = #"01-(200),02-(200),03-(200),04-(200),05-(200),06-(200),07-(200),08-(200),09-
(200),10-(200),11-(200),12-(200),13-(200),14-(200),15-
(200),16-(200),17-(200),18-(200),19-(200),20-(200),21-(200),22-(200),23-(200),24-(200),25-(200),26-
(200),27-(200),28-(200),29-(200),30-(200),31-(
200),32-(200),33-(200),34-(200),35-(200),36-(200),37-(200),38-(200),39-(200),40-(200),41-(200),42-
(200),43-(200),44-(200),45-(200),46-(200),47-(200),48-
(200),49-(200),50-(200),51-(200),52-(200),53-(200),54-(200),55-(200),56-(200),57-(200),58-(200),59-
(200),60-(200),61-(200),62-(200),63-(200),64-
(200),65-(200),66-(200),67-(200),A1111-(200)";
It seems, you should preprocess it in order to remove all new lines, tabulations, spaces etc. and
only then split it:
// Let's remove all white spaces (new lines, tabulations, spaces)
PrintStr = Regex.Replace(PrintStr, #"\s+", "");
// split on comma ',' while ensuring each lines <= 32 characters
var result = string.Join(Environment.NewLine, MySplit(PrintStr, 32, ','));
Console.Write(result);
Outcome:
01-(200),02-(200),03-(200),
04-(200),05-(200),06-(200),
07-(200),08-(200),09-(200),
10-(200),11-(200),12-(200),
13-(200),14-(200),15-(200),
16-(200),17-(200),18-(200),
19-(200),20-(200),21-(200),
22-(200),23-(200),24-(200),
25-(200),26-(200),27-(200),
28-(200),29-(200),30-(200),
31-(200),32-(200),33-(200),
34-(200),35-(200),36-(200),
37-(200),38-(200),39-(200),
40-(200),41-(200),42-(200),
43-(200),44-(200),45-(200),
46-(200),47-(200),48-(200),
49-(200),50-(200),51-(200),
52-(200),53-(200),54-(200),
55-(200),56-(200),57-(200),
58-(200),59-(200),60-(200),
61-(200),62-(200),63-(200),
64-(200),65-(200),66-(200),
67-(200),A1111-(200)
Hope, it's the very picture you want to see after printing

Related

Remove all but specified substring from string

I have a string that contains several instances of a substring, as well as other text. The substring is specified by beginning with a given sequence of letters (e.g. CNTY) and ending with a double slash (//). How could I efficiently remove all text that does not fall inside the specified substring? Thanks for the help. I found that this Regex will return the result needed:
string result = Regex.Matches(text, "CNTY(.*)//").Cast<Match>().Aggregate("", (s, t) => s + t.Value, s => s);
But, I have another more complicated substring, which begins with WEATHLOC, then contains wildcard text across several lines, and ends with a line beginning RMKS, more wildcard text, and then //. Here is an example:
WEATHLOC/ICAO:KCOS//
OBSTIME/052005Z//
WIND/360/10//
VSBY/10/SM//
CLDLYR/-/LYR:BKN//
TEMP/MAXTEMP:15/MINTEMP:18//
ALTSTG/HG:29.92//
RMKS/SAMPLE//
Everything from WEATHLOC to the final // needs to be captured, and I can only rely on its beginning with WEATHLOC and ending with RMKS*//. Is there a way to express that in a Regex match?
This should work:
string text = "hiCNTYhello//content What /-CNTYworld//12texCNTY!//That's it";
string search = "CNTY(.*?)//";
MatchCollection matches = Regex.Matches(text, search);
Will match "hello", "world" and "!"
This little code segment works. The RegEx method was too difficult for me, but this does work. We are trying to check if we are in bounds of CNTY // and to output that text to the StringBuilder.
static void Main(string[] args)
{
var input = #"CNTYTestingTesting//This is some more test CNTY1234//And some moreCNTYWhat is this?//";
var sb = new StringBuilder();
int inCnty = -1;
for (int i = 0; i < input.Length; i ++)
{
// Test for start
if (i < input.Length - 4)
{
if (input.Substring(i, 4) == "CNTY")
{
inCnty = i + 4; // Index of first CNTY
}
}
// Test for end
if (i < input.Length - 1)
{
if (input.Substring(i, 2) == #"//")
{
inCnty = -1; // Reset
}
}
// Test if we are in the segment
if (i >= inCnty && inCnty > 0)
{
// Outside string
sb.Append(input[i]);
}
}
var output = sb.ToString();
Console.WriteLine(output);
Console.Read();
}

C# Console Word Wrap

I have a string with newline characters and I want to wrap the words. I want to keep the newline characters so that when I display the text it looks like separate paragraphs. Anyone have a good function to do this? Current function and code below.(not my own function). The WordWrap function seems to be stripping out \n characters.
static void Main(string[] args){
StreamReader streamReader = new StreamReader("E:/Adventure Story/Intro.txt");
string intro = "";
string line;
while ((line = streamReader.ReadLine()) != null)
{
intro += line;
if(line == "")
{
intro += "\n\n";
}
}
WordWrap(intro);
public static void WordWrap(string paragraph)
{
paragraph = new Regex(#" {2,}").Replace(paragraph.Trim(), #" ");
var left = Console.CursorLeft; var top = Console.CursorTop; var lines = new List<string>();
for (var i = 0; paragraph.Length > 0; i++)
{
lines.Add(paragraph.Substring(0, Math.Min(Console.WindowWidth, paragraph.Length)));
var length = lines[i].LastIndexOf(" ", StringComparison.Ordinal);
if (length > 0) lines[i] = lines[i].Remove(length);
paragraph = paragraph.Substring(Math.Min(lines[i].Length + 1, paragraph.Length));
Console.SetCursorPosition(left, top + i); Console.WriteLine(lines[i]);
}
}
Here is a word wrap function that works by using regular expressions to find the places that it's ok to break and places where it must break. Then it returns pieces of the original text based on the "break zones". It even allows for breaks at hyphens (and other characters) without removing the hyphens (since the regex uses a zero-width positive lookbehind assertion).
IEnumerable<string> WordWrap(string text, int width)
{
const string forcedBreakZonePattern = #"\n";
const string normalBreakZonePattern = #"\s+|(?<=[-,.;])|$";
var forcedZones = Regex.Matches(text, forcedBreakZonePattern).Cast<Match>().ToList();
var normalZones = Regex.Matches(text, normalBreakZonePattern).Cast<Match>().ToList();
int start = 0;
while (start < text.Length)
{
var zone =
forcedZones.Find(z => z.Index >= start && z.Index <= start + width) ??
normalZones.FindLast(z => z.Index >= start && z.Index <= start + width);
if (zone == null)
{
yield return text.Substring(start, width);
start += width;
}
else
{
yield return text.Substring(start, zone.Index - start);
start = zone.Index + zone.Length;
}
}
}
If you want another newline to make text look-like paragraphs, just use Replace method of your String object.
var str =
"Line 1\n" +
"Line 2\n" +
"Line 3\n";
Console.WriteLine("Before:\n" + str);
str = str.Replace("\n", "\n\n");
Console.WriteLine("After:\n" + str);
Recently I've been working on creating some abstractions that imitate window-like features in a performance- and memory-sensitive console context.
To this end I had to implement word-wrapping functionality without any unnecessary string allocations.
The following is what I managed to simplify it into. This method:
preserves new-lines in the input string,
allows you to specify what characters it should break on (space, hyphen, etc.),
returns the start indices and lengths of the lines via Microsoft.Extensions.Primitives.StringSegment struct instances (but it's very simple to replace this struct with your own, or append directly to a StringBuilder).
public static IEnumerable<StringSegment> WordWrap(string input, int maxLineLength, char[] breakableCharacters)
{
int lastBreakIndex = 0;
while (true)
{
var nextForcedLineBreak = lastBreakIndex + maxLineLength;
// If the remainder is shorter than the allowed line-length, return the remainder. Short-circuits instantly for strings shorter than line-length.
if (nextForcedLineBreak >= input.Length)
{
yield return new StringSegment(input, lastBreakIndex, input.Length - lastBreakIndex);
yield break;
}
// If there are native new lines before the next forced break position, use the last native new line as the starting position of our next line.
int nativeNewlineIndex = input.LastIndexOf(Environment.NewLine, nextForcedLineBreak, maxLineLength);
if (nativeNewlineIndex > -1)
{
nextForcedLineBreak = nativeNewlineIndex + Environment.NewLine.Length + maxLineLength;
}
// Find the last breakable point preceding the next forced break position (and include the breakable character, which might be a hypen).
var nextBreakIndex = input.LastIndexOfAny(breakableCharacters, nextForcedLineBreak, maxLineLength) + 1;
// If there is no breakable point, which means a word is longer than line length, force-break it.
if (nextBreakIndex == 0)
{
nextBreakIndex = nextForcedLineBreak;
}
yield return new StringSegment(input, lastBreakIndex, nextBreakIndex - lastBreakIndex);
lastBreakIndex = nextBreakIndex;
}
}

Reverse Words at odd position only C#

This is my code. How can I edit it to show every word which is at the odd position ONLY to be reversed?
for (int i = input.Length - 1; i >= 0; i--)
{
if (input[i] == ' ')
{
result = tmp + " " + result;
tmp = "";
}
else
tmp += input[i];
}
result = tmp + " " + result;
Console.WriteLine(result);
Example input:
"How are you today"
to output:
"How era you yadot"
Based on the position of a word ['How' -> 0] do not reverse; [are -> 1 odd index] Reverse
You can achieve it with the help of LINQ:
var input = "hello this is a test message";
var inputWords = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var result = string.Join(" ",
inputWords.Select((w, i) =>
i % 2 == 0
? w
: new string(w.Reverse().ToArray())
));
Where w in the select is the word, and i is the index, starting at 0 for the first word. % is the modulus operator and gets the remainder. If i % 2 == 0 (i.e. i can be divided by 2 with no remainder), then the original is returned. If there is a remainder (odd) then the reversed word is returned. Finally, it's all wrapped up in a string.Join(" ", items); which turns it back into a normal string rather than an array of items.
Try it online
So far you have a string, like this:
string input = "I want to reverse all odd words (odd words only!).";
And you, naturally, want to perform the task. Now it's the main question what's an odd word?
If you mean word's position (I at position 0, want at 1 - should be reversed etc.)
then you can use regular expressions to match words and Linq to process them:
using System.Linq; // To reverse single word
using System.Text.RegularExpressions; // To match the words within the text
...
// Let's elaborate the test example: add
// 1. some punctuation - ()!. - to preserve it
// 2. different white spaces (spaces and tabulation - \t)
// to add difficulties for naive algorithms
// 3. double spaces (after "to") to mislead split based algorithms
string input = "I want to reverse all\todd words (odd words only!).";
int index = 0; // words' indexes start from zero
string result = Regex.Replace(
input,
"[A-Za-z']+", // word is letters and apostrophes
match => index++ % 2 == 0
? match.Value // Even words intact
: string.Concat(match.Value.Reverse())); // Odd words reversed
Console.WriteLine(result);
If you want to reverse the words with odd Length, i.e. I, all, odd then all you have to do is to change the condition to
match => match.Value % 2 == 0
Outcome:
I tnaw to esrever all ddo words (ddo words ylno!).
Please, notice, that the punctuation has been preserved (only words are reversed).
OP: Based on the position of a word ['How' -> 0] do not reverse; [are -> 1 odd index] Reverse
public static void Main()
{
string input = "How are you today Laken-C";
//As pointed out by #Dmitry Bychenko string input = "How are you today";
//(double space after How) leads to How are uoy today outcome
input = Regex.Replace(input, #"\s+", " ");
var inp = input.Split(' ').ToList();
for (int j = 0; j < inp.Count(); j++)
{
if(j % 2 == 1)
{
Console.Write(inp[j].Reverse().ToArray());
Console.Write(" ");
}
else
Console.Write(inp[j] + " ");
}
}
OUTPUT:
DEMO:
dotNetFiddle
try this is perfect working code..
static void Main(string[] args)
{
string orgstr = "my name is sagar";
string revstr = "";
foreach (var word in orgstr.Split(' '))
{
string temp = "";
foreach (var ch in word.ToCharArray())
{
temp = ch + temp;
}
revstr = revstr + temp + " ";
}
Console.Write(revstr);
Console.ReadKey();
}
Output: ym eman si ragas

How to capitalize the first character of every sentence

Create an application with a method that accepts a string as an argument and returns a copy of the string with the first character of each sentence capitalized.
This is what I have to far and I can't seem to get it right:
//Create method to process string.
private string Sentences(string input)
{
//Capitalize first letter of input.
char firstLetter = char.ToUpper(input[0]);
//Combine the capitalize letter with the rest of the input.
input = firstLetter.ToString() + input.Substring(1);
//Create a char array to hold all characters in input.
char[] letters = new char[input.Length];
//Read the characters from input into the array.
for (int i = 0; i < input.Length; i++)
{
letters[i] = input[i];
}
//Loop through array to test for punctuation and capitalize a character 2 index away.
for (int index = 0; index < letters.Length; index++)
{
if(char.IsPunctuation(letters[index]))
{
if (!((index + 2) >= letters.Length))
{
char.ToUpper(letters[index+ 2]);
}
}
}
for(int ind = 0; ind < letters.Length; ind++)
{
input += letters[ind].ToString();
}
return input;
}
You could use Linq.Aggregate n - see comments in code and code output for explanation how it work's.
This one will respect "Bla. blubb" as well - you need to check for whitespaces after ".?!"
using System;
using System.Linq;
internal class Program
{
static string Capitalize(string oldSentence )
{
return
// this will look at oldSentence char for char, we start with a
// new string "" (the accumulator, short acc)
// and inspect each char c of oldSentence
// comment all the Console.Writelines in this function, thats
// just so you see whats done by Aggregate, not needed for it to
// work
oldSentence
.Aggregate("", (acc, c) =>
{
System.Console.WriteLine("Accumulated: " + acc);
System.Console.WriteLine("Cecking: " + c);
// if the accumulator is empty or the last character of
// trimmed acc is a ".?!" we append the
// upper case of c to it
if (acc.Length == 0 || ".?!".Any(p => p == acc.Trim().Last())) // (*)
acc += char.ToUpper(c);
else
acc += c; // else we add it unmodified
System.Console.WriteLine($"After: {acc}\n");
return acc; // this returns the acc for the next iteration/next c
});
}
static void Main(string[] args)
{
Console.SetBufferSize(120, 1000);
var oldSentence = "This is a testSentence. some occurences "
+ "need capitalization! for examlpe here. or here? maybe "
+ "yes, maybe not.";
var newSentence = Capitalize(oldSentence);
Console.WriteLine(new string('*', 80));
Console.WriteLine(newSentence);
Console.ReadLine();
}
}
(*)
".?!".Any(p => p == ... )) means does the string ".?!" contain any character that equals ...
acc.Trim().Last() means: remove whitespaces in front/on end of acc and give me the last character
.Last() and .Any() are also Linq. Most of the Linq-esc extension can be found here: https://msdn.microsoft.com/en-us/library/9eekhta0(v=vs.110).aspx
Output (snipped - its rather longish ;o)
Accumulated:
Cecking: T
After: T
Accumulated: T
Cecking: h
After: Th
Accumulated: Th
Cecking: i
After: Thi
Accumulated: Thi
Cecking: s
After: This
Accumulated: This
Cecking:
After: This
Accumulated: This
Cecking: i
After: This i
Accumulated: This i
Cecking: s
After: This is
<snipp - .. you get the idea how Aggregate works ...>
Accumulated: This is a testSentence.
Cecking: s
After: This is a testSentence. S
<snipp>
Accumulated: This is a testSentence. Some occurences need capitalization!
Cecking: f
After: This is a testSentence. Some occurences need capitalization! F
<snipp>
********************************************************************************
This is a testSentence. Some occurences need capitalization! For examlpe here. Or here? Maybe yes, maybe not.
I would suggest to use a regex to identify all the dots in your sentence. Get the match, make it upper case and replace it back in the original sentence, in the match index. I dont actually have any IDE in which try the code on .NET right now but i can write it in pseudocode for better understanding.
String setence = "your.setence.goes.here";
Regex rx = new Regex("/\..*?[A-Z]/");
foreach (Match match in rx.Matches(sentence))
{
setence.remove(match.Index, 2).insert(match.Index, String.ToUpper(match.Value));
}
You have two tasks:
1) Split text into sentences
2) Capitalize the first char in the sentences
Task one can be very complex, e.g. because there a lot of crazy languages out there. Put since this is homework I assume you can go ahead and simply split by well know separators.
Task two is just about basic string operations. You select the first char, make it uppercase and add the missing part of the sentence via a substring operation.
Here is a code example:
char[] separators = new char[] { '!', '.', '?' };
string[] sentencesArray = "First sentence. second sentence!lastone.".Split(separators, StringSplitOptions.RemoveEmptyEntries);
var i = 0;
Array.ForEach(sentencesArray, e =>
{
sentencesArray[i] = e.Trim().First().ToString().ToUpper() +
e.Trim().Substring(1);
i++;
});
I Have created a method in Groovy for the same
String capitalizeFirstCharInSentence(String str) {
String result = ''
str = str.toLowerCase()
List<String> strings = str.tokenize('.')
strings.each { line ->
StringBuilder builder = new StringBuilder(line)
int i = 0
while (i < builder.size() - 1 && !Character.isLowerCase(builder.charAt(i))) {
i++
}
if (Character.isLowerCase(builder.charAt(i))) {
builder.setCharAt(i, builder.charAt(i).toUpperCase())
result += builder.toString() + '.'
}
}
return result
}
I liked the way you formatted your method because it made it easy for newer coders to read so I decided to try to make the code work while maintaining the structure. The main problem I saw was that you were not replacing the arrays after formatting them.
//Create method to process string.
private string Sentences(string input)
{
//Create a char array to hold all characters in input.
char[] letters = new char[input.Length];
//Read the characters from input into the array.
for (int i = 0; i < input.Length; i++)
{
letters[i] = input[i];
}
//Capitalize first letter of input.
letters[0] = char.ToUpper(letters[0]);
//Loop through array to test for punctuation and capitalize a character 2 index away.
for (int index = 0; index < letters.Length; index++)
{
if(char.IsPunctuation(letters[index]))
{
if (index + 2 <= letters.Length)
{
letters[index + 2] = char.ToUpper(letters[index+ 2]);
}
}
}
// convert array back to string
string results = new string(letters)
return results;
}

Replace consecutive characters with same single character

I was just wondering if there is a simple way of doing this. i.e. Replacing the occurrence of consecutive characters with the same character.
For eg: - if my string is "something likeeeee tttthhiiissss" then my final output should be "something like this".
The string can contain special characters too including space.
Can you guys suggest some simple way for doing this.
This should do it:
var regex = new Regex("(.)\\1+");
var str = "something likeeeee!! tttthhiiissss";
Console.WriteLine(regex.Replace(str, "$1")); // something like! this
The regex will match any character (.) and \\1+ will match whatever was captured in the first group.
string myString = "something likeeeee tttthhiiissss";
char prevChar = '';
StringBuilder sb = new StringBuilder();
foreach (char chr in myString)
{
if (chr != prevChar) {
sb.Append(chr);
prevChar = chr;
}
}
How about:
s = new string(s
.Select((x, i) => new { x, i })
.Where(x => x.i == s.Length - 1 || s[x.i + 1] != x.x)
.Select(x => x.x)
.ToArray());
In english, we are creating a new string based on a char[] array. We construct that char[] array by applying a few LINQ operators:
Select: Capture the index i along with the current character x.
Filter out charaters that are not the same as the subsequent character
Select the character x.x back out of the anonymous type x.
Convert back to a char[] array so we can pass to constructor of string.
Console.WriteLine("Enter any string");
string str1, result="", str = Console.ReadLine();
char [] array= str.ToCharArray();
int i=0;
for (i = 0; i < str.Length;i++ )
{
if ((i != (str.Length - 1)))
{ if (array[i] == array[i + 1])
{
str1 = str.Trim(array[i]);
}
else
{
result += array[i];
}
}
else
{
result += array[i];
}
}
Console.WriteLine(result);
In this code the program ;
will read the string as entered from user
2.Convert the string in char Array using string.ToChar()
The loop will run for each character in string
each character stored in that particular position in array will be compared to the character stored in position one greater than that . And if the characters are found same the character stored in that particular array would be trimmed using .ToTrim()
For last character the loop will show error of index out of bound as it would be the last position value of the array. That's why I used * if ((i != (str.Length - 1)))*
6.The characters left after trimming are stored in result in concatenated form .
word = "something likeeeee tttthhiiissss"
re.sub(r"(.)\1+", r"\1",word)

Categories