I am writing a program that writes to a file that requires specific positions:
it looks something like:
writer.WriteLine("{0,-3}{1,-5}{2,-30}", data1, data2, data3);
The positions that it starts is correct however, if data1 exceeds 3 character, it pushes the format by the exceeded amount,
Is there a way to make data1 cap at 3 characters and ignore any excess characters using the writeline format?
If I understood correctly, you should "safely substring" (Substring throws an exception if you choose a length greater than the string length) your strings to the desidered lenght.
public static string SafeSubstring(this string text, int start, int length)
{
return text.Length <= start ? string.Empty
: text.Length - start <= length ? text.Substring(start)
: text.Substring(start, length);
}
Then, for example:
writer.WriteLine("{0,-3}{1,-5}{2,-30}",
data1.SafeSubstring(0, 3),
data2.SafeSubstring(0, 3),
data3.SafeSubstring(0, 3));
Use string.Substring. This code trims the string if it's longer than 3 characters:
Console.WriteLine("{0,-3}{1,-5}{2,-30}",
data1.Substring(0,data1.Length > 3 ? 3 : data1.Length),
data2, data3);
You can't solve this with formatting alone, but you can implement a (extension) method:
public static string ToLength(this object value, int length) {
if (length == 0)
return "";
else if (null == value)
return new string(' ', Math.Abs(length));
string v = value.ToString();
if (v.Length >= Math.Abs(length))
return v.Substring(0, Math.Abs(length));
else if (length < 0)
return v.PadRight(-length);
else
return v.PadLeft(length);
}
Then use it
writer.WriteLine("{0}{1}{2}",
data1.ToLength(-3),
data2.ToLength(-5),
data3.ToLength(-30));
I've implemented extension method for object, not string since you may want to put any object to stream.
Related
i have a string of length 98975333 and i need to remove first 5 letters in it. Can anyone suggest the best way to do this keeping performance in mind?
I tried
str.Substring(5,str.Length);
str.Remove(0,5);
which gives me result in 0.29 sec
but i want something even faster than the above.
Problem Using StringBuilder
-> i need to substring a part of the string and to do this i need to write
StringBuilder2.ToString().Substring(anyvaluehere)"
here the conversion of StringBuilder to string by ".ToString()" takes time and in this case i cant use StringBuilder
If you are working with long strings, always use StringBuilder. This class provides you fast adding and removing characters, faster than String.Concat or it's syntactic sugar "a" + "b". Moreover StringBuilder.ToString() method has special implementation for best performance as possible.
Sorry, c# strings are not arrays; they are immutable so extracting a (possibly very long) substring involves a copy.
However, most [string utilities] accept start and end indices, for instance IndexOf and CompareInfo.Compare all take a startIndexoverload.
Perhaps if you tell us what you want to do afterward we could suggest alternatives?
Update
Here are some ways you can write performant string parsing with the immutable strings in c#. Say for instance that you need to deserialize XML data inside the string, and need to skip the first N characters. You could do something like this:
public static object XmlDeserializeFromString<T>(this string objectData, int skip)
{
var serializer = new XmlSerializer(typeof(T));
using (var reader = new StringReader(objectData))
{
for (; skip > 0 && reader.Read() != -1; skip--)
;
return (T)serializer.Deserialize(reader);
}
}
As you can see from the source. StringReader.Read() does not make a copy of the unread portion of the string, it keeps an internal index to the remaining unread portion.
Or say you want to skip the first N characters of a string, then parse the string by splitting it at every "," character. You could write something like this:
public static IEnumerable<Pair<int>> WalkSplits(this string str, int startIndex, int count, params char[] separator)
{
if (string.IsNullOrEmpty(str))
yield break;
var length = str.Length;
int endIndex;
if (count < 0)
endIndex = length;
else
{
endIndex = startIndex + count;
if (endIndex > length)
endIndex = length;
}
while (true)
{
int nextIndex = str.IndexOfAny(separator, startIndex, endIndex - startIndex);
if (nextIndex == startIndex)
{
startIndex = nextIndex + 1;
}
else if (nextIndex == -1)
{
if (startIndex < endIndex)
yield return new Pair<int>(startIndex, endIndex - 1);
yield break;
}
else
{
yield return new Pair<int>(startIndex, nextIndex - 1);
startIndex = nextIndex + 1;
}
}
}
And then use the start and end indices of the Pair to further parse the string, or extract small substrings to feed to further parsing methods.
(Pair<T> is a small struct I created similar to KeyValuePair<TKey, TValue> but with identically typed first and second values. I can provide if needed.)
Using a StringBuilder to produce and manipulate the string will help you save on resources:
StringBuilder sb = new StringBuilder();
sb.Append("text"); //to add text in front
sb.Insert(50,"text"); // to insert text
sb.Remove(50,4); // to remove text
sb.ToString(); // to produce the string
If you have a fixed length of string that you wish to store elsewhere, you can make a char array and use StringBuilder's CopyTo() method:
e.g.
char[] firstfive = new char[5];
sb.CopyTo(0,firstfive,0,5);
Edit:
Actually, the OP figured this out himself, but I'm including it on the post for reference:
To get a portion of the StringBuilder as string:
sb.ToString(intStart,intLength)
Use String.Remove() i.e
String newStr = "";
newStr = str.Remove(0,5); //This will delete 5 characters starting from 0 index
Or
newStr = str.Remove(5); //Assumes the starting position as 0 and will ddelete 5 chars from that
Read more Here
Does anyone know of an implementation of the php function mb_strcut in C#?
http://php.net/manual/en/function.mb-strcut.php
mb_strcut() extracts a substring from a string similarly to mb_substr(), but operates on bytes instead of characters. If the cut position happens to be between two bytes of a multi-byte character, the cut is performed starting from the first byte of that character. This is also the difference to the substr() function, which would simply cut the string between the bytes and thus result in a malformed byte sequence.
Thanks Dash could have not written the below without your help
public static string LimitByteLength(string input, int startByte, int byteLength)
{
var maxLength = startByte + byteLength;
return
new string(
input.SkipWhile((c, i) => GetByteCount(input.Substring(0, i + 1)) <= startByte)
.TakeWhile((c, i) => GetByteCount(input.Substring(0, i + 1)) <= maxLength).ToArray());
}
private static int GetByteCount(string input)
{
return Encoding.Unicode.GetByteCount(input);
}
When I have a string that I want to cut into a new string from a certain Index to a certain Index, which function do I use?
If the string was:
ABCDEFG
This would mean retrieving BCD when the two indexes specified were 1 and 3.
If endIndex points to the last character that you want to have included in the extracted substring:
int length = endIndex - startIndex + 1;
string extracted = s.Substring(startIndex, length);
If endIndex points to the first character following the desired substring (i.e. to the start of the remaining text):
int length = endIndex - startIndex;
string extracted = s.Substring(startIndex, length);
See String.Substring Method (Int32, Int32) for the official description on Microsoft Docs.
Since C# 8.0, in .NET Core and .NET 5+ only, you can use Indices and ranges
string extracted = s[startIndex..endIndex];
where the position at endIndex is excluded. This corresponds to my second example with Substring where endIndex points to the first character following the desired substring (i.e. to the start of the remaining text).
If endIndex is intended to point to the last character that you want to have included, just add one to endIndex:
string extracted = s[startIndex..(endIndex + 1)];
This becomes possible with the new Range feature of C# 8.0.
An extension method on string that uses Range to achieve this is:
public static class StringExtensions
{
public static string SubstringByIndexes(this string value, int startIndex, int endIndex)
{
var r = Range.Create(startIndex, endIndex + 1);
return value[r];
/*
// The content of this method can be simplified down to:
return value[startIndex..endIndex + 1];
// by using a 'Range Expression' instead of constructing the Range 'long hand'
*/
}
}
Note: 1 is added to endIndex when constructing the Range that's used as the end of the range is exclusive, rather than inclusive.
Which can be called like this:
var someText = "ABCDEFG";
var substring = someText.SubstringByIndexes(1, 3);
Giving a value of BCD in substring.
Unfortunately, C# doesn't natively have what you need. C# offers Substring(int startIndex, int length) instead. To achieve Substring(int startIndex, int endIndex), you will need custom implementation. Following extension method can make reusability easier/cleaner:
public static class Extensions
{
public static string Substring2(this string value, int startIndex, int endIndex)
{
return value.Substring(startIndex, (endIndex - startIndex + 1));
}
}
There is two way to substring string..
1 )
public string Substring(
int startIndex
)
Retrieves a substring from this instance. The substring starts at a specified character position.
2)
public string Substring(
int startIndex,
int length
)
Retrieves a substring from this instance. The substring starts at a specified character position and has a specified length.
I need to get the letters as an array on passing two letters using C#
For ex.: When i pass "AE", i need to get the {A,B,C,D,E} as an array. and passing "FJ" should return {F,G,H,I,J}.
The Enumerable class can create a range, which makes the looping simple:
public static char[] CharactersBetween(char start, char end) {
return Enumerable.Range(start, end - start + 1).Select(c => (char)c).ToArray();
}
Note: A char value converts implicitly into int, so there is no conversion needed in that direction. You only have to convert the integers back to char.
Edit:
If you want to send in the alphabet to use (to handle language differences), you can use Substring to get a part of that string:
public static char[] CharactersBetween(char start, char end, string alphabet) {
int idx = alphabet.IndexOf(start);
return alphabet.Substring(idx, alphabet.IndexOf(end) - idx + 1).ToCharArray();
}
Do you mean something like
char[] CharactersBetween(char start, char end)
{
List<char> result = new List<char>();
for (char i = start; i <= end; i++)
{
result.Add(i);
}
return result.ToArray();
}
This should work out well
string startandend = "AG";
string result= "";
for( char i = startandend[0]; i <= startandend[1]; i++){
result += i;
}
result will now contain ABCDEFG.
You should probably add some logic to check if startandend actually have a Length of 2 and so on, but this should be a good starting block for you.
If you want the char[] instead of the string representation, simply call result.ToCharArray() at the end.
Use a loop with integer conversion
with
System.Convert.ToInt32(Char);
and
System.Convert.ToChar(Int32);
see http://msdn.microsoft.com/en-us/library/system.convert_methods.aspx
Pretty simple if you use a fixed alphabet,
public static string ALPHABET = "ABCDEFGHIJKLMNOPWRSTUVWXYZ";
public static List<char> GetLetters(string firstLast)
{
List<char> letters = new List<char>();
int start = ALPHABET.IndexOf(firstLast[0]);
int end = ALPHABET.IndexOf(firstLast[1]);
for (int i = start; i <= end; i++)
{
letters.Add(ALPHABET[i]);
}
return letters;
}
Obviously add in your checks for various things, but it does the basic job.
You're going to have to reference whichever alphabet you want to use. English is easy enough as the letters happen to correspond to code-point order, French treats Œ and Æ as letters in their own right sometimes, and not others. Danish and Norwegian place "Æ, Ø, Å" after Z and Swedish does the same with "Å, Ä, Ö". Irish uses "ABCDEFGHILMNOPRSTU" as the alphabet, but does also use J, K, Q, V, W, X, Y & Z in loan words.
And those are relatively easy cases. So there's no one-size-fits-all.
The easiest way to pass an alphabet is to have a string that contains it. So, e.g. the Danish alphabet would have the string "ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ" while French could either include the ligatures or not as you wish (but do you need to deal with the possibility of receiving them while not using them?).
This done:
public static IEnumerable<char> AlphabetRange(string alphabet, string alphaRange)
{
if(alphaRange == null)
throw new ArgumentNullException();
if(alphaRange.Length < 2)
throw new ArgumentException();
int startIdx = alphabet.IndexOf(alphaRange[0]);
int endIdx = alphabet.IndexOf(alphaRange[1]) + 1;
if(startIdx == -1 || endIdx == 0)
throw new ArgumentException();
while(startIdx < endIdx)
yield return alphabet[startIdx++];
}
I need to solve the following question which i can't get to work by myself(newbie^^)..:
Ok, the question: Create a method which will print the central letter of a string (given as a parameter). I need to use the property lenght to determine the lenght.
So for example the string: Books. the middle/central letter is o.
Hope its a bit clear..
Thanks in advance.
Edit: I know how to determine the lenght of the string. Now the problem is to divide the word and then write down the next letter or something.
Here are some tips:
1. Type string has a Length property.
2 .If you know the index of the character you want, you can ask for it using: myString[index].
3. Knowing what to do with string that has even number of characters is necessary to answer that question.
4. Consider integer devision.
That should get you started.
string middleLetter(string arg)
{
return arg[arg.Length >> 1];
}
public static string FindMiddleChar(string s)
{
int middleChar = s.Length / 2;
if (s.Length > 2)
{
if (s.Length % 3 == 0)
{
if (s.Length <= 3)
{
return s[middleChar].ToString();
}
return s[middleChar - 1] + s[middleChar].ToString();
}
else if (s.Length % 3 != 0)
{
if (s.Length <= 4)
{
return s[middleChar - 1] + s[middleChar].ToString();
}
return s[middleChar].ToString();
}
}
return "Error, the input string must contain at least three characters.";
}