Can I "multiply" a string (in C#)?

99

Solution 1

In .NET 4 you can do this:

String.Concat(Enumerable.Repeat("Hello", 4))

Solution 2

Note that if your "string" is only a single character, there is an overload of the string constructor to handle it:

int multipler = 10;
string TenAs = new string ('A', multipler);

Solution 3

Unfortunately / fortunately, the string class is sealed so you can't inherit from it and overload the * operator. You can create an extension method though:

public static string Multiply(this string source, int multiplier)
{
   StringBuilder sb = new StringBuilder(multiplier * source.Length);
   for (int i = 0; i < multiplier; i++)
   {
       sb.Append(source);
   }

   return sb.ToString();
}

string s = "</li></ul>".Multiply(10);

Solution 4

I'm with DrJokepu on this one, but if for some reason you did want to cheat using built-in functionality then you could do something like this:

string snip = "</li></ul>";
int multiplier = 2;

string result = string.Join(snip, new string[multiplier + 1]);

Or, if you're using .NET 4:

string result = string.Concat(Enumerable.Repeat(snip, multiplier));

Personally I wouldn't bother though - a custom extension method is much nicer.

Solution 5

Just for the sake of completeness - here is another way of doing this:

public static string Repeat(this string s, int count)
{
    var _s = new System.Text.StringBuilder().Insert(0, s, count).ToString();
    return _s;
}

I think I pulled that one from Stack Overflow some time ago, so it is not my idea.

Share:
99
Chromo
Author by

Chromo

Updated on August 25, 2020

Comments

  • Chromo
    Chromo over 3 years

    I'm coding a small socket Chat Server for personal use, and have come across and issue. My client is a simple program with two threads, one waiting on a user input, the other on the server; this code works perfectly:

    import socket
    import threading
    from threading import Thread
    
    username = input("Username? >")
    host = input("host ip?")
    port = 8000
    
    Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    Socket.connect((host,port))
    Socket.send(username.encode())
    print(Socket.recv(1024).decode())
    
    def SendMessage():
    
        while True:
    
            Socket.send(input("").encode())
    
    def RecvMessage():
    
        while True:
    
            print(Socket.recv(1024).decode())
    
    msgthread = Thread(target = SendMessage, args = ())
    recvthread = Thread(target = RecvMessage, args = ())
    
    msgthread.start()
    recvthread.start()
    

    (Forgive the sloppy code, it was thrown together in ~20mins on a Monday evening) As you can see, I am calling two threads, both of which have halting functions in them, and it works seamlessly.

    The server, however, is where I am having problems:

    import socket
    import threading
    from threading import Thread
    
    connections = []
    host = ""
    port = 8000
    threads = []
    
    def ListenForCommands():
    
        while True:
    
            print(input())
    
    def SearchForConnections():
    
        global connections, threads
    
        while True:
    
            conn, addr = Socket.accept()
            username = conn.recv(10).decode()
    
            conn.send(("You have successfully connected to the server!").encode()) 
            print(username + " (" + str(addr[0]) + ":" + str(addr[1]) + ") Joined")
    
            for i in range(len(connections)):
                if connections[i][0] != conn:
                    connections[i][0].send((username + " Joined").encode())
    
            connections += [[conn,addr,username]]
    
            threads += [Thread(target = Listen, args = (conn, ))]
            threads[-1].start()
    
    def Listen(conn):
    
        global connections, threads
    
        while True:
    
            for i in range(len(connections)):
    
                    if connections[i][0] == conn:
    
                        username = connections[i][2]
    
            try:
    
                data = conn.recv(1024).decode()
                print(username + ": " + data)
    
                for i in range(len(connections)):
    
                    if connections[i][0] != conn:
    
                        connections[i][0].send((username + ": " + data).encode())
    
            except:
    
                print(username + " Disconnected")
    
                for i in range(len(connections)):
    
                    if connections[i][0] == conn:
    
                        connections.remove(connections[i])
                        break
    
                for i in range(len(connections)):
    
                    connections[i][0].send((username + " Disconnected").encode())
    
                return;
    
    Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print("Server created")
    Socket.bind((host,port))
    
    Socket.listen(3)
    
    ListenThread = Thread(target = ListenForCommands, args = ())
    ListenThread.start()
    SearchForConnections()
    

    The source of the problem is in these functions:

    def ListenForCommands():
    
        while True:
    
            print(input())
    
    def SearchForConnections():
    
        global connections, threads
    
        while True:
    
            conn, addr = Socket.accept()
            username = conn.recv(10).decode()
    
            conn.send(("You have successfully connected to the server!").encode()) 
            print(username + " (" + str(addr[0]) + ":" + str(addr[1]) + ") Joined")
    
            for i in range(len(connections)):
                if connections[i][0] != conn:
                    connections[i][0].send((username + " Joined").encode())
    
            connections += [[conn,addr,username]]
    
            threads += [Thread(target = Listen, args = (conn, ))]
            threads[-1].start()
    

    The program seems to be halting when arriving at this line

    print(username + " (" + str(addr[0]) + ":" + str(addr[1]) + ") Joined")
    

    and works fine without it; however, on the Client Program, this does not seem to be the case.

    the ListenForCommands function (as of now just printing out the user input) is being declared as a thread:

    ListenThread = Thread(target = ListenForCommands, args = ())
    ListenThread.start()
    

    and the SearchForConnections function is being called normally. However, the entire program seems to be being halted until an input is taken from the user, unlike the client side which seems to be working perfectly.

    I think I am missing something quite obvious, but have been at a loss for a few hours now, and would love it if someone could help me see the error in my ways!

  • Marc Gravell
    Marc Gravell over 15 years
    Just where I was going! You could probably optimize by using source.Length * multiplier in the StringBuilder ctor
  • Marc Gravell
    Marc Gravell over 15 years
    You need (source.Length * multiplier), not just (multiplier)
  • Tamas Czinege
    Tamas Czinege over 15 years
    Marc: Are you sure that it means characters and not items?
  • Tamas Czinege
    Tamas Czinege over 15 years
    Sorry, apparently it is characters.
  • ShigaSuresh
    ShigaSuresh over 15 years
    Nice, thanks guys, I was hoping for something like the pythonesque (@Vasil) but this will do it more nicely that what I was about to do :D
  • Jronny
    Jronny almost 14 years
    I never knew there was a cheat like this. =)
  • Will Dean
    Will Dean almost 14 years
    Didn't even .NET3 have Enumerable.Repeat?
  • Marc Gravell
    Marc Gravell almost 14 years
    @Will - .NET 3 was WCF/WPF etc, so no; it does exist in .NET 3.5, but then you'd need to string.Join it as well - why not just loop n times? Much more direct.
  • Will Dean
    Will Dean almost 14 years
    Thanks - I wasn't thinking properly about 3.0 vs 3.5. As to why not just use a loop, surely that's the whole essence of the functional vs imperative debate? I posted a .net 4 answer lower down which I think is not too bad in the 'functional cleverness' vs 'looping obviousness' debate.
  • Kobi
    Kobi almost 14 years
    To get a single string you'd still need String.Concat, and on 3.5 you'd also need .ToArray(). Not the most elegant solution, I'm afraid.
  • Gabe
    Gabe almost 14 years
    I hope you don't really use ParallelEnumerable in situations like this. string.Join needs to use the elements in order, so parallelizing their generation is uncalled for.
  • Jronny
    Jronny almost 14 years
    @Gabe: Since the items are the same and are really just copies of thisString, there's no need to worry about the ordering here, I guess.
  • sehe
    sehe about 13 years
    I agree with many teachers in the field that it is usually is good to code to say what you mean. There is no benefit to say you want this parallel and only secretly think "Well, I know it won't be parallel in this particular case anyway"
  • Jronny
    Jronny over 12 years
    I think making it parallel makes it faster, or please enlighten me. That's why I'm converting this to ParallelEnumerable, thus I think I code to say what I mean... Thanks.
  • Mark Foreman
    Mark Foreman over 11 years
    And it's not much more in .NET 3.5: String.Concat(Enumerable.Repeat("Hello", 4).ToArray())
  • demented hedgehog
    demented hedgehog almost 9 years
    I don't think it's elegant at all. In python the code to do this is: snip * multiplier (It's not horrible.. but neither is it beautiful).
  • Will Dean
    Will Dean almost 9 years
    @dementedhedgehog I know you acknowledge your own dementia, but even suffering as you do, you might be able to see that a Python example wouldn't have made a very good answer to a C# question... I think most of us can see that language selection is always a compromise, and pretty much any answer to any question could be footnoted with advocacy, either for or against.
  • demented hedgehog
    demented hedgehog almost 9 years
    @will dean: I was just referring to Matthew Nichols statement about the elegance of the code you have there. As far as I can tell your code is elegant for C#, as it currently stands, for this problem. The point I'm trying to make is: (I believe) it would be very easy (for microsoft, as strings are sealed) to extend C# to overload the * operator to allow int * string multiplication. Which would then actually be elegant in some universal sense, imho, not just elegant within the context of the constraints imposed by C# as it exists at the moment.
  • TEK
    TEK over 7 years
    @dementedhedgehog To me, that goes against what binary operator* represents. To each their own, I guess.
  • demented hedgehog
    demented hedgehog over 7 years
    Yeah.. I can appreciate that. Potentially breaks strong typing... could lead to weird errors if you weren't careful. (I still like python grammar+stdlibs much better for string manipulation).
  • Raymond Reddington
    Raymond Reddington over 4 years
    This is really pro.