I am having a problem whereby the letter at the position(e.g 39) would be replaced with the text I wanted to input. However what I want was to insert the text at position 39 instead of replacing it. Anyone please guide me on this.
string description = variables[1]["value"].ToString();// where I get the text
int nInterval = 39;// for every 39 characters in the text I would have a newline
string res = String.Concat(description.Select((c, z) => z > 0 && (z % nInterval) == 0 ? Environment.NewLine +"Hello"+(((z/ nInterval)*18)+83).ToString()+"world": c.ToString()));
file_lines = file_lines.Replace("<<<terms_conditions>>>",resterms); //file_lines is where I read the text file
Original text
Present this redemption slip to receive: One
After String.Concat
Present this redemption slip to receive\r\n\u001bHello101world
One //: is gone
I am also having a issue where I want to put a new line if it contains * in the text. If anybody is able to help that would be great.
Edit:
What I want to achieve is something like this
Input
*Item is considered paid if unsealed.*No replacement or compensation will be given for any expired coupons.
so like i need to find every 39 character and also * to input newline so it will be
Output
*Item is considered paid if unsealed.
*No replacement or compensation will be
given for any expired coupons.
Try String.Insert(Int32, String) Method
Insert \n where you need new line.
If I understood your question properly, you want a newline after every 39 characters. You can use string.Insert(Int32, String) method for that.
And use String.Replace(String, String) for your * problem.
Below code snippet doing that using a simple for loop.
string sampleStr = "Lorem Ipsum* is simply..";
for (int i = 39; i < sampleStr.Length; i = i + 39){
sampleStr = sampleStr.Insert(i, Environment.NewLine);
}
//sampleStr = sampleStr.Replace("*", Environment.NewLine);
int[] indexes = Enumerable.Range(0, sampleStr.Length).Where(x => sampleStr[x] == '*').ToArray();
for (int i = 0; i < indexes.Length; i++)
{
int position = indexes[i];
if (position > 0) sampleStr = sampleStr.Insert(position, Environment.NewLine);
}
If you want to do both together
int[] indexes = Enumerable.Range(0, sampleStr.Length).Where(x => sampleStr[x] == '*' || x % 39 == 0).ToArray();
int j = 0;
foreach (var position in indexes)
{
if (position > 0)
{
sampleStr = sampleStr.Insert(position + j, Environment.NewLine);
j = j + 2; // increment by two since newline will take two chars
}
}
Without debating the method chosen to achieve the desired result, the problem with the code is that at the 39th character it adds some text, but the character itself has been forgotten.
Changing the following line should give the expected output.
string res = String.Concat(description.Select((c, z) => z > 0 && (z % nInterval) == 0 ? Environment.NewLine + "Hello" + (((z / nInterval) * 18) + 83).ToString() + "world" + c.ToString() : c.ToString()));
<== UPDATED ANSWER BASED ON CLARIFICATION IN QUESTION ==>
This will do what you want, I believe. See comments in line.
var description = "*Item is considered paid if unsealed.*No replacement or compensation will be given for any expired coupons.";
var nInterval = 39; // for every 39 characters in the text I would have a newline
var newline = "\r\n"; // for clarity in the Linq statement. Can be set to Environment.Newline if desired.
var z = 0; // we'll handle the count manually.
var res = string.Concat(
description.Select(
(c) => (++z == nInterval || c == '*') // increment z and check if we've hit the boundary OR if we've hit a *
&& ((z = 0)==0) // resetting the count - this only happens if the first condition was true
? newline + (c == ' ' ? string.Empty : c.ToString()) // if the first character of a newline is a space, we don't need it
: c.ToString()
));
Output:
*Item is considered paid if unsealed.
*No replacement or compensation will be
given for any expired coupons.
Related
I want to add space between every 3 characters in a string in C#, but count from right to left.
For example :
11222333 -> 11 222 333
Answer by #Jimi from comments (will delete if they post their own)
var YourString = "11222333";
var sb = new StringBuilder(YourString);
for (int i = sb.Length -3; i >= 0; i -= 3)
sb.Insert(i, ' ');
return sb.ToString();
The benefit of this algorithm appears to be that you are working backwards through the string and therefore only moving a certain amount on each run, rather than the whole string.
If you are trying to format a string as a number according to some locale conventions you can use the NumberFormat class to set how you want a number to be formatted as a string
So for example
string input = "11222333";
NumberFormatInfo currentFormat = new NumberFormatInfo();
currentFormat.NumberGroupSeparator = " ";
if(Int32.TryParse(input, NumberStyles.None, currentFormat, out int result))
{
string output = result.ToString("N0", currentFormat);
Console.WriteLine(output); // 11 222 333
}
The following recursive function would do the job:
string space3(string s)
{
int len3 = s.Length - 3;
return (len <= 0) ? s
: (space3(s.Substring(0, len3)) + " " + s.Substring(len3));
}
C# 8.0 introduced string ranges. Ranges allow for a more compact form:
string space3(string s)
{
return (s.Length <= 3) ? s
: (space3(s[..^3]) + " " + s[^3..]);
}
Using Regex.Replace:
string input = "11222333";
string result = Regex.Replace( input, #"\d{3}", #" $0", RegexOptions.RightToLeft );
Demo and detailed explanation of RegEx pattern at regex101.
tl;dr: Match groups of 3 digits from right to left and replace them by space + the 3 digits.
The most efficient algorithm I can come up with is the following:
var sb = new StringBuilder(YourString.Length + YourString.Length / 3 + 1);
if (YourString.Length % 3 > 0)
{
sb.Append(YourString, 0, YourString.Length % 3);
sb.Append(' ');
}
for (var i = YourString.Length % 3; i < YourString.Length; i += 3)
{
sb.Append(YourString, i, 3);
sb.Append(' ');
}
return sb.ToString();
We first assign a StringBuilder of the correct size.
Then we check to see if we need to append the first one or two characters. Then we loop the rest.
dotnetfiddle
I have been working on trying to get Azure translator to convert text stored in a database column. Here is a couple of examples of how the text is currently stored:
eg1. "Add %%objectives%% from predefined sets of %%objectives%%"
eg2. %%Risk%%
eg3. some text here %%model%%. Please refresh the page.
My goal is to translate everything but the data within the % %. The problem is with Azure translate it has to be within the syntax of <div class="notranslate">" "" which means I have to replace all of the %% with that syntax. I was able to convert this and it works with only 1 within the string but everything else seemed to go down a rabbit hole. Here is my code:
english = "Add %%objectives%% from predefined sets of %%objectives%%";
if (english.Contains("%%"))
{
Dictionary<int, int> positions = new Dictionary<int, int>(); // this is to hold the locations of where delims are in string
ArrayList l = new ArrayList();
char[] letters = english.ToCharArray();
// get the first location of %
for (int i = 0; i < english.Length; i++)
{
if (letters[i] == '%')
{
l.Add(i);
}
}
string temp = "";
// only works if theres 1 % in the string
if (l.Count == 4)
{
int loc = english.IndexOf('%'); //%%Model%% = 0
int lastloc = english.LastIndexOf('%');
temp = " <div class=\"notranslate\">" + english.Substring(loc + 2, (lastloc - 3) - loc) + "</div>";
var lang = Translate(convert(english, temp), "en", "it");
// need to convert back to %%
Console.WriteLine(lang);
dataNode.SelectSingleNode("value").InnerText = lang;
}
else if (l.Count > 4) //this means that there are more than 1 delimted
{
foreach(int i in l) // 4 , 5 , 16 ,17, 43, 44
// % % text % % text % %
{
}
Any help is appreciated!
Do not replace the '%%'. Insert the <div class="notranslate"> before any odd sequence number '%%' and insert the </div> after any even sequence number '%%'. This way, the translation retains the %% markup.
If you have the option to translate the string after the variables have been replaced with real, human-readable values, you will get a better translation out of it.
To illustrate:
Take the input string "Yesterday I ate two bu rgers" (space intentional)
I want to check the input string to see if a space (or any other pre-defined character) " " exists between the two characters (in this case) "u" and "r". And if it exists delete this character.
First I came up with this:
string someString = "Yesterday I ate two bu rgers";
string charA = 'u', charB = 'r';
if (someString.Contains(charA) &&
someString.Substring(someString.IndexOf(charA) + 1).Equals(" ") &&
someString.Substring(someString.IndexOf(charA) + 2).Equals(charB))
//delete the space
However not only does this feel (and look) inefficient as heck, It also fails if the sentence would be "Yesterday you ate two bu rgers" since it will take the index of the first "u". So I would have to do an additional check for multiple instances of charA
Another solution I thought of is to split the sentence on every space, and see if the last character of the split matches charA and the first character of the next split matches charB. And if it does join the two together.
string[] splitString = someString.Split(null);
for (int i = 0; i < splitString.Length -1; i++)
{
string lastChar = splitString[i].Substring(splitString[i].Length - 1);
string firstChar = splitString[i + 1].Substring(0, 1);
if(lastChar.Equals(charA) && firstChar.Equals(charB))
{
string joined = splitString[i] + splitString[i + 1];
}
}
However this method is also flawed as it breaks when i.e two spaces are present in the input.
Is there a way to do this without needing a bunch of if statements or loops? (unless there really is no other way I would really like to not use regex)
A string is an array of characters. Loop through it and inspect the characters.
for (int i = 2; i < someString.Length; i++) {
if (someString[i] == charB && someString[i - 2] == charA) {
//TODO: delete the char in between.
break;
}
}
If you start at index = 2 and test for the second character, you can simply go back by 2 positions to inspect the first one.
But of course you could also look ahead like this:
for (int i = 0; i < someString.Length - 2; i++) {
if (someString[i] == charA && someString[i + 2] == charB) {
//TODO: delete the char in between.
break;
}
}
Iam working on a project in Unity3d, using C# scripting, with strings that are written in Hebrew and English.
The problem with Unity3d is that RTL languages (like Hebrew) are not supported when writing UI texts.
The problem looks like this:
original text:
מערכת העטלף הינה מערכת, אשר מתבססת על טכנולוגית ה- GPR
(Ground Penetrating Radar) - ראדאר חודר קרקע.
in unity:
GPR -ה תיגולונכט לע תססבתמ רשא ,תכרעמ הניה ףלטעה תכרעמ
.עקרק רדוח ראדאר - (Ground Penetrating Radar)
Iam trying to hack the order that the text is printed to the text boxes for a month now and I cant get it just right.
I made up the following function:
public string CorrectText (string text)
{
string result = "";
string temp = "";
string charListString = "";
List<Char> charList = new List<char> ();
char[] charArray = text.ToCharArray ();
Array.Reverse (charArray);
//go through each char in charArray
for (int x = 0; x <= charArray.Length -1; x++) {
//if the current char we're examing isn't a Space char -
if (!char.IsWhiteSpace (charArray [x])) {
//add it to charList
charList.Add (charArray [x]);
} else { //if the current char we're examing is a Space char -
charListString = new string (charList.ToArray ());
//if charListString doesn't contains English or Numeric chars -
if (!Regex.IsMatch (charListString, "^[0-9a-zA-Z.,()-]*$")) {
//go through each char in charList
for (int y = 0; y <= charList.Count - 1; y++) {
//add the current char to temp as is (not flipped)
temp += charList [y];
}
//add temp to result
if (x < charArray.Length - 1)
result += temp + " ";
if (x == charArray.Length - 1)
result += temp;
//clear charList and temp
charList.Clear ();
temp = "";
} else { //if temp contains English or Numeric chars -
//go through each char in charList - This flipps the order of letters
for (int y = charList.Count - 1; y >= 0; y--) {
//add the current char to temp
temp += charList [y];
}
//add temp to result
if (x < charArray.Length - 1)
result += temp + " ";
if (x == charArray.Length - 1)
result += temp;
//clear charList and temp
charList.Clear ();
temp = "";
}
}
}
return result;
}
this almost fixed the problem, but the text is written from bottom up for example:
input:
מערכת העטלף הינה מערכת, אשר מתבססת על טכנולוגית ה- GPR
(Ground Penetrating Radar) - ראדאר חודר קרקע.
output:
(Ground Penetrating Radar) - ראדאר חודר קרקע.
מערכת העטלף הינה מערכת, אשר מתבססת על טכנולוגית ה- GPR
and sometimes the parenthesis are getting mixed up in the sentence, showing like this:
)Ground Penetrating( Radar - ראדאר חודר קרקע.
I've found a tool online that turns Visual Hebrew to Logic Hebrew, and when I copied the flipped text to unity it worked like magic!
But I cant find any useful information online on how to make my own script with C# that does the same thing.
I managed to overcome this... sort of:
Assign the string into the text element.
Force the canvas to update using Canvas.ForceUpdateCanvases(), or another means.
Get the cached text generator (NOT for layout) of the text component. It will lie to you if you didn't force an update or yielded and waited for the next frame; so don't skip step 2.
Use getLines of the cached text generator to get the information of the text wrapping; it holds the index where every line starts.
Take the maximum difference in the values of those and you have the likely amount of characters per row before it wraps.
Insert '\n' (new line) into the original string manually using the row length you found in the previous step before flipping the characters!
Do the reversal process on the wrapped string. If you do these things in a different order you will end up with the first line being the shortest, instead of the last. So wrap first, reverse second.
Set the string to the text component and it should work. Usually.
For example, a user entered "I love this post!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
the consecutive duplicate exclamation mark "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" should be detected.
The following regular expression would detect repeating chars. You could up the number or limit this to specific characters to make it more robust.
int threshold = 3;
string stringToMatch = "thisstringrepeatsss";
string pattern = "(\\d)\\" + threshold + " + ";
Regex r = new Regex(pattern);
Match m = r.Match(stringToMatch);
while(m.Success)
{
Console.WriteLine("character passes threshold " + m.ToString());
m = m.NextMatch();
}
Here's and example of a function that searches for a sequence of consecutive chars of a specified length and also ignores white space characters:
public static bool HasConsecutiveChars(string source, int sequenceLength)
{
if (string.IsNullOrEmpty(source))
return false;
if (source.Length == 1)
return false;
int charCount = 1;
for (int i = 0; i < source.Length - 1; i++)
{
char c = source[i];
if (Char.IsWhiteSpace(c))
continue;
if (c == source[i+1])
{
charCount++;
if (charCount >= sequenceLength)
return true;
}
else
charCount = 1;
}
return false;
}
Edit fixed range bug :/
Can be done in O(n) easily: for each character, if the previous character is the same as the current, increment a temporary count. If it's different, reset your temporary count. At each step, update your global if needed.
For abbccc you get:
a => temp = 1, global = 1
b => temp = 1, global = 1
b => temp = 2, global = 2
c => temp = 1, global = 2
c => temp = 2, global = 2
c => temp = 3, global = 3
=> c appears three times. Extend it to get the position, then you should be able to print the "ccc" substring.
You can extend this to give you the starting position fairly easily, I'll leave that to you.
Here is a quick solution I crafted with some extra duplicates thrown in for good measure. As others pointed out in the comments, some duplicates are going to be completely legitimate, so you may want to narrow your criteria to punctuation instead of mere characters.
string input = "I loove this post!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!aa";
int index = -1;
int count =1;
List<string> dupes = new List<string>();
for (int i = 0; i < input.Length-1; i++)
{
if (input[i] == input[i + 1])
{
if (index == -1)
index = i;
count++;
}
else if (index > -1)
{
dupes.Add(input.Substring(index, count));
index = -1;
count = 1;
}
}
if (index > -1)
{
dupes.Add(input.Substring(index, count));
}
The better way i my opinion is create a array, each element in array is responsible for one character pair on string next to each other, eg first aa, bb, cc, dd. This array construct with 0 on each element.
Solve of this problem is a for on this string and update array values.
You can next analyze this array for what you want.
Example: For string: bbaaaccccdab, your result array would be { 2, 1, 3 }, because 'aa' can find 2 times, 'bb' can find one time (at start of string), 'cc' can find three times.
Why 'cc' three times? Because 'cc'cc & c'cc'c & cc'cc'.
Use LINQ! (For everything, not just this)
string test = "aabb";
return test.Where((item, index) => index > 0 && item.Equals(test.ElementAt(index)));
// returns "abb", where each of these items has the previous letter before it
OR
string test = "aabb";
return test.Where((item, index) => index > 0 && item.Equals(test.ElementAt(index))).Any();
// returns true