4

Is there a fast way (without having to explicitly looping through each character in a string) and either stripping or keeping it. In Visual FoxPro, there is a function CHRTRAN() that does it great. Its on a 1:1 character replacement, but if no character in the alternate position, its stripped from the final string. Ex

CHRTRAN( "This will be a test", "it", "X" )

will return

"ThXs wXll be a es"

Notice the original "i" is converted to "X", and lower case "t" is stripped out.

I looked at the replace for similar intent, but did not see an option to replace with nothing.

I'm looking to make some generic routines to validate multiple origins of data that have different types of input restrictions. Some of the data may be coming from external sources, so its not just textbox entry validation I need to test for.

Thanks

DRapp
  • 47,638
  • 12
  • 72
  • 142

6 Answers6

9

All you need is a couple of calls to String.Replace().

string s = "This will be a test";
s = s.Replace("i", "X");
s = s.Replace("t", "");

Note that Replace() returns a new string. It does not alter the string itself.

Jon B
  • 51,025
  • 31
  • 133
  • 161
5

Does this what you want?

"This will be a test".Replace("i", "X").Replace("t", String.Empty)

Here is a simple implementation of the CHRTRAN function - it does not work if the string contains \0 and is quite messy. You could write a nicer one using loops, but I just wanted to try it using LINQ.

public static String ChrTran(String input, String source, String destination)
{
    return source.Aggregate(
        input,
        (current, symbol) => current.Replace(
            symbol,
            destination.ElementAtOrDefault(source.IndexOf(symbol))),
        preResult => preResult.Replace("\0", String.Empty));
}

And the you can use it.

// Returns "ThXs wXll be a es"
String output = ChrTran("This will be a test", "it", "X");

Just to have a clean solution - the same without LINQ and working for the \0 cases, too, and it is almost in place because of using a StringBuilder but won't modify the input, of course.

public static String ChrTran(String input, String source, String destination)
{
    StringBuilder result = new StringBuilder(input);

    Int32 minLength = Math.Min(source.Length, destination.Length);

    for (Int32 i = 0; i < minLength; i++)
    {
        result.Replace(source[i], destination[i]);
    }

    for (Int32 i = minLength; i < searchPattern.Length; i++)
    {
        result.Replace(source[i].ToString(), String.Empty);
    }

    return result.ToString();
}

Null reference handling is missing.

Inspired by tvanfosson's solution, I gave LINQ a second shot.

public static String ChrTran(String input, String source, String destination)
{
    return new String(input.
        Where(symbol =>
            !source.Contains(symbol) ||
            source.IndexOf(symbol) < destination.Length).
        Select(symbol =>
            source.Contains(symbol)
                ? destination[source.IndexOf(symbol)]
                : symbol).
        ToArray());
}
Daniel Brückner
  • 59,031
  • 16
  • 99
  • 143
  • Don't know why the replace wasn't working for me originally, but the String.Empty worked... Although I'm not into Linq, what you had in context was a similar looping mechanism I would have done knowing there wasn't a direct equivalent... I'm on my way... Thanks – DRapp May 12 '09 at 12:35
5

Here was my final function and works perfectly as expected.

public static String ChrTran(String ToBeCleaned, 
                             String ChangeThese, 
                             String IntoThese)
{
   String CurRepl = String.Empty;
   for (int lnI = 0; lnI < ChangeThese.Length; lnI++)
   {
      if (lnI < IntoThese.Length)
         CurRepl = IntoThese.Substring(lnI, 1);
      else
         CurRepl = String.Empty;

      ToBeCleaned = ToBeCleaned.Replace(ChangeThese.Substring(lnI, 1), CurRepl);
   }
   return ToBeCleaned;
}
DRapp
  • 47,638
  • 12
  • 72
  • 142
  • 1
    I know this is a very old thread, but this function does not work as expected. It only works if ChangeThese/IntoThese don't contain the same characters. This is because the String.Replace function will replace certain characters multiple times under certain conditions. If you take ChrTran("Alfabet", "ABab12", "21baBA"), you would expect the output to be "2lfbaet". The actual output however is "Alfaaet". The "A" will be replaced by a "2", but later on that "2" will get replaced again with "A". You need to loop through the input string and replace char by char to prevent double replaces. – RiptoR Jan 11 '17 at 12:44
  • @RiptoR, you appear to have a good point, but not in the way originally intended the routine to work. In the intended usage, I would not have been doing the same letters in both strings, but duly noted. – DRapp Jan 11 '17 at 15:20
  • My apologies. I came across this while looking for a .NET equivalent of Python's translate/maketrans functions so I was thinking in terms of how those functions work. – RiptoR Jan 11 '17 at 16:38
4

This is a case where I think using LINQ overcomplicates the matter. This is simple and to the point:

private static string Translate(string input, string from, string to)
{
    StringBuilder sb = new StringBuilder();
    foreach (char ch in input)
    {
        int i = from.IndexOf(ch);
        if (from.IndexOf(ch) < 0)
        {
            sb.Append(ch);
        }
        else
        {
            if (i >= 0 && i < to.Length)
            {
                sb.Append(to[i]);
            }
        }
    }
    return sb.ToString();
}
Robert Rossney
  • 94,622
  • 24
  • 146
  • 218
3

To "replace with nothing", just replace with an empty string. This will give you:

String str = "This will be a test";
str = str.Replace("i", "X");
str = str.Replace("t","");
Meta-Knight
  • 17,626
  • 1
  • 48
  • 58
3

A more general version as a string extension. Like the others this does not do a translation in place since strings are immutable in C#, but instead returns a new string with the replacements as specified.

public static class StringExtensions
{
    public static string Translate( this string source, string from, string to )
    {
        if (string.IsNullOrEmpty( source ) || string.IsNullOrEmpty( from ))
        {
            return source;
        }

        return string.Join( "", source.ToCharArray()
                                   .Select( c => Translate( c, from, to ) )
                                   .Where( c => c != null )
                                   .ToArray() );
    }

    private static string Translate( char c, string from, string to )
    {
        int i = from != null ? from.IndexOf( c ) : -1;
        if (i >= 0)
        {
            return (to != null && to.Length > i)
                      ? to[i].ToString()
                      : null;
        }
        else
        {
            return c.ToString();
        }
    }
}
tvanfosson
  • 524,688
  • 99
  • 697
  • 795