String contains another two strings - c#

Is it possible to have the contain function find if the string contains 2 words or more?
This is what I'm trying to do:
string d = "You hit someone for 50 damage";
string a = "damage";
string b = "someone";
string c = "you";
if(d.Contains(b + a))
{
Console.WriteLine(" " + d);
Console.ReadLine();
}
When I run this, the console window just shuts down really fast without showing anything.
And another question: if I for one want to add how much damage is done, what would be the easiest way to get that number and get it into a TryParse?

You would be better off just calling Contains twice or making your own extension method to handle this.
string d = "You hit someone for 50 damage";
string a = "damage";
string b = "someone";
string c = "you";
if(d.Contains(a) && d.Contains(b))
{
Console.WriteLine(" " + d);
Console.ReadLine();
}
As far as your other question, you could build a regular expression to parse the string to find 50 or if the string is always the same, just split it based on a space and get the 5th part.

public static class StringExtensions
{
public static bool Contains(this string s, params string[] predicates)
{
return predicates.All(s.Contains);
}
}
string d = "You hit someone for 50 damage";
string a = "damage";
string b = "someone";
string c = "you";
if (d.Contains(a, b))
{
Console.WriteLine("d contains a and b");
}

That is because the if statements returns false since d doesn't contain b + a i.e "someonedamage"

Are you looking for the string contains a certain number of words or contains specific words? Your example leads towards the latter.
In that case, you may wish to look into parsing strings or at least use regex.
Learn regex - it will be useful 1000x over in programming. I cannot emphasize this too much. Using contains and if statements will turn into a mess very quickly.
If you are just trying to count words, then :
string d = "You hit someone for 50 damage";
string[] words = d.Split(' '); // Break up the string into words
Console.Write(words.Length);

With the code d.Contains(b + a) you check if "You hit someone for 50 damage" contains "someonedamage". And this (i guess) you don't want.
The + concats the two string of b and a.
You have to check it by
if(d.Contains(b) && d.Contains(a))

This is because d does not contain b + a (i.e. "someonedamage"), and therefore the application just terminates (since your Console.ReadLine(); is within the if block).

Your b + a is equal "someonedamage", since your d doesn't contain that string, your if statement returns false and doesn't run following parts.
Console.WriteLine(" " + d);
Console.ReadLine();
You can control this more efficient as;
bool b = d.Contains(a) && d.Contains(b);
Here is a DEMO.

string d = "You hit someone for 50 damage";
string a = "damage";
string b = "someone";
string c = "you";
if(d.Contains(a) && d.Contains(b))
{
Console.WriteLine(" " + d);
}
Console.ReadLine();

If you have a list of words you can do a method like this:
public bool ContainWords(List<string> wordList, string text)
{
foreach(string currentWord in wordList)
if(!text.Contains(currentWord))
return false;
return true;
}

You could write an extension method with linq.
public static bool MyContains(this string str, params string[] p) {
return !p.Cast<string>().Where(s => !str.Contains(s)).Any();
}
EDIT (thx to sirid):
public static bool MyContains(this string str, params string[] p) {
return !p.Any(s => !str.Contains(s));
}

Because b + a ="someonedamage", try this to achieve :
if (d.Contains(b) && d.Contains(a))
{
Console.WriteLine(" " + d);
Console.ReadLine();
}

So you want to know if one string contains two other strings?
You could use this extension which also allows to specify the comparison:
public static bool ContainsAll(this string text, StringComparison comparison = StringComparison.CurrentCulture, params string[]parts)
{
return parts.All(p => text.IndexOf(p, comparison) > -1);
}
Use it in this way (you can also omit the StringComparison):
bool containsAll = d.ContainsAll(StringComparison.OrdinalIgnoreCase, a, b);

I just checked for a space in contains to check if the string has 2 or more words.
string d = "You hit someone for 50 damage";
string a = "damage";
string b = "someone";
string c = "you";
bool a = ?(d.contains(" ")):true:false;
if(a)
{
Console.WriteLine(" " + d);
}
Console.Read();

So what is that you are really after? If you want to make sure that something has hit for damage (in this case), why are you not using string.Format
string a = string.Format("You hit someone for {d} damage", damage);
In this way, you have the ability to have the damage qualifier that you are looking for, and are able to calculate that for other parts.

string d = "You hit ssomeones for 50 damage";
string a = "damage";
string b = "someone";
if (d.Contains(a) && d.Contains(b))
{
Response.Write(" " + d);
}
else
{
Response.Write("The required string not contain in d");
}

public static bool In(this string str, params string[] p)
{
foreach (var s in p)
{
if (str.Contains(s)) return true;
}
return false;
}

class Program {
static void Main(String[] args) {
// By using extension methods
if ( "Hello world".ContainsAll(StringComparison.CurrentCultureIgnoreCase, "Hello", "world") )
Console.WriteLine("Found everything by using an extension method!");
else
Console.WriteLine("I didn't");
// By using a single method
if ( ContainsAll("Hello world", StringComparison.CurrentCultureIgnoreCase, "Hello", "world") )
Console.WriteLine("Found everything by using an ad hoc procedure!");
else
Console.WriteLine("I didn't");
}
private static Boolean ContainsAll(String str, StringComparison comparisonType, params String[] values) {
return values.All(s => s.Equals(s, comparisonType));
}
}
// Extension method for your convenience
internal static class Extensiones {
public static Boolean ContainsAll(this String str, StringComparison comparisonType, params String[] values) {
return values.All(s => s.Equals(s, comparisonType));
}
}

Related

After instruction still can not make for loop with C# [duplicate]

This question already has answers here:
How do I create a terminable while loop in console application?
(7 answers)
Closed 3 years ago.
I started a C# course now and there is an assignment where I have to create a "palindrome detector" program. Point is that user inputs some word or sentence, then I have to remove chars like ,.;:!? and space from it. I have done that with two different methods, because char method can not remove space so I wrote another method for it.
After "cleaning" operation program reversing input what user gave, and comparing original user input and reversed user input to each other. It they are same it prints "It is palindrome", if they are different it prints "It is not palindrome". That is working fine, BUT THE PROBLEM IS I have to put them in for loop. It have to ask input again and again, until user give empty.
This would be very easy, but somehow I can not do it.
Here is my code:
using System;
namespace Palindromi
{
class Program
{
static void Main()
{
Console.WriteLine("Hei! Tervetuloa palindromin tunnistusohjelmaan. Tämä tunnistaa, onko syöttämäsi sana sama toisinpäin!");
Console.Write("Anna teksti (tyhjä lopettaa): ");
string userinput = Console.ReadLine(); //userinput is user's input, this is what you have to modify. remove some chars and reverse it.
if (userinput == "")
{
Console.ReadLine();//when i have loop this have to be "break". This meant to break for loop when i have it.
}
char[] removechars = { '.', ':', ';', ',', '!', '?' };//this is the list of "have to be removed" chars
string userinput_without_chars = userinput.Trim(removechars); //this method remove chars which are listed
string userinput_without_chars_space = userinput_without_chars.Replace( " ", ""); //replace space with empty
string reverse_string, reversed;
reverse_string = userinput_without_chars_space;
reversed = "";
int len;
len = userinput_without_chars_space.Length - 1;
while (len >= 0)
{
reversed = reversed + reverse_string[len];
len--;
}
Console.WriteLine("Sana käännettynä on {0}", reversed); //tells user input reversed
if (userinput_without_chars_space == reversed)//check is the userinput same than reversed user input
{
Console.Write("On palindromi.");//it is palindrome
}
else
{
Console.Write("Ei ole palindromi.");//it is not palindrome
}
}
}
}
You could potentially do something along these lines:
var running = true;
while(running)
{
var input = Console.ReadLine().ToLower();
var phrase = input.Sanitize(new List<string>() {".", ",", "?", "!", "'", "&", "%", "$", " "});
if(phrase.IsPalindrome())
Console.Writeline("Input was palindrome.");
}
public static string Sanitize(this string input, IList<string> punctuation) =>
String.Join(String.Empty, input.Where(character => punctuation.Contains(character) == false));
public static bool IsPalindrome(this string sentence)
{
for (int l = 0, r = sentence.Length - 1; l < r; l++, r--)
if (sentence[l] != sentence[r])
return false;
return true;
}
public static void Close(string input)
{
// Some logic to see if the application should stop.
}
You could create another method that looks for commands, or keystrokes, then sets the boolean to run as false. Which would break the infinite loop. You could also do an abrupt close with Environment.Exit.
The very simplest approach is replace your Console.ReadLine() where you want to break to return.
Alternatively, you could wrap the logic in another while loop.
while (userinput != "")
{
// Remove chars
// rest of your logic
/* IMPORTANT */
userinput = Console.Readline();
}
To remove the symbols from the input, you can use the Regex.Replace method. In this case, you can be sure, that the specified symbols will be correctly removed from the input string. Note, that you can handle the whitespaces along with other characters you mentioned, like in the code snippet below:
var CharactersToRemove { get; set; } = " ,.;:!?";
var processedInput = Regex.Replace(input.ToLower(), $"[{CharactersToRemove}]", string.Empty);
Note, that here I used input.ToLower() to convert the input to a lowercase string. This will make the palindrome tests case-insensitive. Should you need case-sensitive palindrome tests, just remove the .ToLower() part.
There is no need to reverse the input string to check if it is a palindrome. You can check this within one for loop as follows:
bool CheckForBeingaAPalindrome(string input)
{
var frontIndex = 0;
var tailIndex = input.Length - 1;
for (; frontIndex < tailIndex;)
{
if (input[frontIndex] != input[tailIndex])
return false;
++frontIndex;
--tailIndex;
}
return true;
}
Note, that in this case you only iterate over the elements of the input string once. This approach will give you al least 4 times better performance than the one you used.
Below, you can find a complete minimal working solution to your problem.
using System.Text.RegularExpressions;
using static System.Console;
namespace Assignment
{
public static class PalindromeFinder
{
public static string CharactersToRemove { get; set; } = " ,.;:!?";
public static bool IsPalindrome(string input)
{
var processedInput = RemoveUnnecessaryCharacters(input);
return CheckForBeingAPalindrome(processedInput);
}
private static string RemoveUnnecessaryCharacters(string input)
{
return Regex.Replace(input.ToLower(), $"[{CharactersToRemove}]", string.Empty);
}
private static bool CheckForBeingAPalindrome(string input)
{
var frontIndex = 0;
var tailIndex = input.Length - 1;
for (; frontIndex < tailIndex;)
{
if (input[frontIndex] != input[tailIndex])
return false;
++frontIndex;
--tailIndex;
}
return true;
}
}
public class Program
{
private static void Main(string[] args)
{
ContinuouslyCheckUserInputForBeingAPalindrome();
}
private static void ContinuouslyCheckUserInputForBeingAPalindrome()
{
while (FetchUserInputFromConsole() is string input
&& !string.IsNullOrWhiteSpace(input))
{
var isPalindrome = PalindromeFinder.IsPalindrome(input);
var modifier = isPalindrome ? "a" : "not a";
WriteLine($"It is {modifier} palindrome");
}
}
private static string FetchUserInputFromConsole()
{
Write("Enter a string: ");
return ReadLine();
}
}
}

How to correctly convert letters to numbers?

I have a string which comprise lots of letters. I have used the following code to convert it to numbers, but the new string t still gives me imperfect result.
For example:
tung2003 -> -1-1-1-12003
What I expected: 1161171101032003 (116 is the ASCII code of t, 117 is the ASCII code of u
string t=null;
foreach (char c in Properties.Settings.Default.password)
{
int ascii = (int)Char.GetNumericValue(c);
int counter=0;
counter = ascii;
t = t + Convert.ToString(counter);
}
The problem is the - character. I want my new string only comprises numbers.
It looks like you do not want the ASCII values of the numbers based on your expected output. In that case you can just do something like this:
string input = "tung2003";
string output = string.Empty;
foreach(char c in input)
{
if(char.IsNumber(c))
{
output += c;
}
else
{
output += ((byte)c).ToString();
}
}
//output is now: 1161171101032003
Fiddle here
Also added as a Linq expression for a short hand solution.
// Method 1 Linq
string output = string.Concat(("tung2003".ToCharArray()
.Select(s=> char.IsDigit(s) ? s.ToString() : ((int)s).ToString())));
// Method 2
string input = "tung2003";
string output = string.Empty;
foreach (char c in input)
{
if (Char.IsDigit(c)) output += c.ToString();
else output += ((int)c).ToString();
}
Extrapolating your output it looks like you want two different things. You want to tally each ascii character as long as it is a letter and extract the numeric values to append. The following provides three options, the first is to tally the ascii values from letters and the other two are ways to extract only digits. Because your code example uses a Password I am assuming you are trying to do some sort of custom hashing and if that is the case you should use a Hash implementation from the Cryptography namespace or some other package.
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
var combined = OnlyLettersToAscii("tung2003") + OnlyNumbers("tung2003");
Console.WriteLine($"Input: tung2003 Output: {OnlyNumbers("tung2003")}");
Console.WriteLine($"Input: tung2003 Output Regex: {OnlyNumbersWithRegex("tung2003")}");
Console.ReadKey();
}
private static string OnlyLettersToAscii(string originalString)
{
if (string.IsNullOrWhiteSpace(originalString)) return originalString;
return string.Join(string.Empty, originalString.ToArray()
.Where(w => char.IsLetter(w))
.Select(s => ((int)s).ToString()));
}
private static string OnlyNumbers(string originalString)
{
if (string.IsNullOrWhiteSpace(originalString)) return originalString;
return new string(originalString.Where(w => char.IsDigit(w)).ToArray());
}
public static string OnlyNumbersWithRegex(string originalString)
{
return Regex.Replace(originalString, #"[^\d]", string.Empty);
}
}
}
string t = "";
foreach (char c in Properties.Settings.Default.password)
{
if (IsNumber(x)) t += System.Convert.ToInt32(c).ToString();
else
{
t += c.ToString();
}
}
Moreover, if you just want to get rid off '-' the use this code: t =String.Replace(t, '-');

Checking if string contains numeric value, then display the value doubled

user input:
"I have 3 apples"
output:
"I"
"have"
"6"
"apples"
My C#:
static void Main(string[] args)
{
Console.WriteLine("Enter a string...");
string delimeter = " ";
string input = Console.ReadLine();
string[] output = input.Split(Convert.ToChar(delimeter));
foreach (var substring in output)
{
Console.WriteLine(substring);
}
Console.Read();
}
I need help getting on the right track. My code only breaks the sentence apart using space as a delimiter.
Give it a try
foreach (var substring in output)
{
int value;
if(int.TryParse(substring, out value)){
value = value * 2;
input = input.Replace(substring, value.ToString());
}
}
Console.WriteLine(input);
You first need to check if your spitted string is a number, if it is then multiple by 2 and replace it in your input variable to get the expected output.
Can you try followoing?
static void Main(string[] args)
{
Console.WriteLine("Enter a string...");
string delimeter = " ";
string input = Console.ReadLine();
var result = System.Text.RegularExpression.Regex.Replace(input,"\d+", match=>(int.Parse(match.Value)*2).ToString(CultureInfo.InvariantCul‌​ture));
Console.WriteLine(result);
Console.Read();
}
Here is an algorithm for example.
// an extension method to check if a string is all decimal digits
public static class StringHelper {
public static bool IsNumeric(this string str)
{
if (str.IsNullOrWhiteSpace()) return false;
return str.All(char.IsNumber);
}
}
...
static void Main(string[] args)
{
Console.WriteLine("Enter a string...");
string delimeter = " ";
string input = Console.ReadLine();
string[] output = input.Split(Convert.ToChar(delimeter));
foreach (var substring in output)
{
if (substring.IsNumeric())
{
substring = (int.Parse(substring) * 2).ToString();
}
Console.Write(substring);
}
Console.WriteLine();
Console.Read();
}
Please note that the code is only checking if a substring contains only decimal digits. It's not prepared to handle any number with decimal point for example, and it's also not completely safe. The code is not tested, and is ment only for example purposes.
I intentionally showed a code without using Regular Expressions, but if you're interested, check out the other answers for that alternative.

How to remove all characters from a string before a specific character

Suppose I have a string A, for example:
string A = "Hello_World";
I want to remove all characters up to (and including) the _. The exact number of characters before the _ may vary. In the above example, A == "World" after removal.
string A = "Hello_World";
string str = A.Substring(A.IndexOf('_') + 1);
You have already received a perfectly fine answer. If you are willing to go one step further, you could wrap up the a.SubString(a.IndexOf('_') + 1) in a robust and flexible extension method:
public static string TrimStartUpToAndIncluding(this string str, char ch)
{
if (str == null) throw new ArgumentNullException("str");
int pos = str.IndexOf(ch);
if (pos >= 0)
{
return str.Substring(pos + 1);
}
else // the given character does not occur in the string
{
return str; // there is nothing to trim; alternatively, return `string.Empty`
}
}
which you would use like this:
"Hello_World".TrimStartUpToAndIncluding('_') == "World"
string a = "Hello_World";
a = a.Substring(a.IndexOf("_")+1);
try this? or is the A= part in your A=Hello_World included?
var foo = str.Substring(str.IndexOf('_') + 1);
string orgStr = "Hello_World";
string newStr = orgStr.Substring(orgStr.IndexOf('_') + 1);
you can do this by creating a substring.
simple exampe is here:
public static String removeTillWord(String input, String word) {
return input.substring(input.indexOf(word));
}
removeTillWord("I need this words removed taken please", "taken");

String.Format Phone Numbers with Extension

I am trying to create a an function that formats US phone numbers -- hopefully without looping through each digit.
When 10 digits are passed in all is fine. How ever when more than 10 digits are passed in
I want the String.Format method to append the extension digits on the right. For example:
When 14 digits passed in the result should be:(444)555-2222 x8888
When 12 digits passed in the result should be:(444)555-2222 x88
etc.
However what I get with my current attempt is:
Passing in 12 digits returns this string '() -949 x555444433'
here is what I have so far.
public static string _FormatPhone(object phonevalue)
{
Int64 phoneDigits;
if (Int64.TryParse(phonevalue.ToString(), out phoneDigits))
{
string cleanPhoneDigits = phoneDigits.ToString();
int digitCount = cleanPhoneDigits.Length;
if (digitCount == 10)
return String.Format("{0:(###) ###-####}", phoneDigits);
else if (digitCount > 10)
return String.Format("{0:(###) ###-#### x#########}", phoneDigits);
else
return cleanPhoneDigits;
}
return "Format Err#";
}
Thanks in advance.
I think you'll have to break your phoneDigits string into the first 10 digits and the remainder.
//[snip]
else if (phoneDigits.ToString().Length > 10)
{
return String.Format("{0:(###) ###-#### x}{1}", phoneDigits.Substring(0,10), phoneDigits.Substring(10) );
}
//[snip]
I'd suggest treating it as a string of digits, not a number. You would then use Substring explicitly to break out the parts.
Trying to squeeze it into 1 line, I came up with this.
var phoneNumber = "(999) 555-4455 ext123";
phoneNumber = Regex.Replace(phoneNumber, "(.*?)([+]\\d{1,3})?(.*?)(\\d{3})(.*?)(\\d{3})(.*?)(\\d{4})([ ]+)?(x|ext)?(.*?)(\\d{2,5})?(.*?)$", "$2 $4 $6 $8 $10$12").Trim().Replace("ext","x");
If it starts with +# it will leave that alone. It will then look for blocks of numbers. 3,3,4 then it looks for ext or x for extension and another 2-5 numbers. At that point you can format it anyway you like, I chose spaces.
1234567890 -> '123 456 7890'
(123)456.7890 -> '123 456 7890'
+1 (999)555-4455 ext123 -> '+1 999 555 4455 x123'
The problem lies in your else if condition where you have a set number of # placeholders to handle the phone number extension. Instead, we can define the format dynamically to account for different lengths.
Why are you passing in an object? You're using ToString() all over the place. Why not pass in a string from the start? If the item you're passing in isn't a string then call ToString before passing it in, or save the ToString() result in a variable in the method as shown below.
Here's an updated version of your method:
public static string _FormatPhone(object phonevalue)
{
string returnPhone = "Format Err#";
Int64 phoneDigits;
string phoneNumber = phonevalue.ToString();
if (Int64.TryParse(phoneNumber, out phoneDigits))
{
if (phoneNumber.Length == 10)
{
return phoneDigits.ToString("(###) ###-####");
}
else if (phoneNumber.Length > 10)
{
// determine the length of placeholders needed for the format
string format = "(###) ###-#### x"
+ new string('#', phoneNumber.Length - 10);
return phoneDigits.ToString(format);
}
else
{
return phoneNumber;
}
}
return returnPhone;
}
To test it:
string[] inputs = { "456", "4445552222", "444555222288", "44455522226789" };
foreach (string input in inputs)
{
Console.WriteLine("Format Result: " + _FormatPhone(input));
}
There's no need for a regex in this case. If you really wanted to use one though, your replacement method needs to determine the length in order to append the extension when needed as shown below:
string[] inputs = { "456", "4445552222", "444555222288", "44455522226789" };
string pattern = #"(\d{3})(\d{3})(\d{4})(\d*)";
foreach (string input in inputs)
{
string result = Regex.Replace(input, pattern, m =>
{
if (m.Value.Length >= 10)
{
return String.Format("({0}) {1}-{2}",
m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value)
+ (m.Value.Length > 10 ? " x" + m.Groups[4].Value : "");
}
return m.Value;
});
Console.WriteLine("Regex result: " + result);
}
using a regex:
Regex usPhoneRegex = new Regex(#"(\d{3})(\d{3})(\d{4})(.*)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
string USPhoneFormatString = "$1-$2-$3 x$4";
return usPhoneRegex.Replace("312588230012999", USPhoneFormatString));
Anything after the main phone number will be returned as an extension
Since you were using an int64 in your code, my regex assumes there are no spaces or punctuation in the phone number.
-- Edit --
Ahmad pointed out that I was not handling the case of a number without an extension. So here is a revised version that uses a MatchEvaluator to do the job. Is it better than the other answers? I don't know - but it is a different approach so I thought I would toss it out there.
Regex usPhoneRegex = new Regex(#"(\d{3})(\d{3})(\d{4})(.*)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
return usPhoneRegex.Replace("3125882300", new MatchEvaluator(MyClass.formatPhone))
public static string formatPhone(Match m) {
int groupIndex = 0;
string results = string.Empty;
foreach (Group g in m.Groups) {
groupIndex +=1;
switch (groupIndex) {
case 2 :
results = g.Value;
break;
case 3 :
case 4 :
results += "-" + g.Value;
break;
case 5 :
if (g.Value.Length != 0) {
results += " x " + g.Value;
}
break;
}
}
return results;
}
This should probably use a StringBuilder.
Try using regular expressions:
class Program
{
static void Main(string[] args)
{
var g = FormatUSPhone("444555222234");
}
public static string FormatUSPhone(string num)
{
string results = string.Empty;
if(num.Length == 10)
{
num = num.Replace("(", "").Replace(")", "").Replace("-", "");
const string formatPattern = #"(\d{3})(\d{3})(\d{4})";
results = Regex.Replace(num, formatPattern, "($1) $2-$3");
}else if (num.Length == 12)
{
num = num.Replace("(", "").Replace(")", "").Replace("-", "");
const string formatPattern = #"(\d{3})(\d{3})(\d{4})(\d{2})";
results = Regex.Replace(num, formatPattern, "($1) $2-$3 x$4");
}
return results;
}
I edited the above from an example I found here. Play about with the above code, see if it helps you.

Categories

Resources