Thread overview
Modify char in string
May 18, 2014
Tim
May 18, 2014
bearophile
May 18, 2014
Chris Cain
May 19, 2014
Tim
May 19, 2014
Ali Çehreli
May 18, 2014
Hi everyone,

is there any chance to modify a char in a string like:

void main()
{
   string sMyText = "Replace the last char_";
   sMyText[$ - 1] = '.';
}

But when I execute the code above I'm always getting "cannot modify immutable expression at sMyText[__dollar -1LU]". I though D supported such modifications anytime. How can I do that now...?
May 18, 2014
Tim:

> is there any chance to modify a char in a string like:
>
> void main()
> {
>    string sMyText = "Replace the last char_";
>    sMyText[$ - 1] = '.';
> }
>
> But when I execute the code above I'm always getting "cannot modify immutable expression at sMyText[__dollar -1LU]". I though D supported such modifications anytime. How can I do that now...?

D strings are immutable. And mutating immutable variables is a bug in D. So you can't do that. You have to work around the problem. One solution is to not have a string, but something more like a char[] in the first place, and mutate it.

If you have a string, you can do (this works with the current GIT DMD compiler):



/// Not Unicode-safe.
string dotLast(in string s) pure nothrow {
    auto ds = s.dup;
    ds[$ - 1] = '.';
    return ds;
}

void main() {
    import std.stdio;

    immutable input = "Replace the last char_";
    immutable result = input.dotLast;
    result.writeln;
}


That code doesn't work if your text contains more than the Ascii chars.

Bye,
bearophile
May 18, 2014
On Sunday, 18 May 2014 at 18:55:59 UTC, Tim wrote:
> Hi everyone,
>
> is there any chance to modify a char in a string like:

As you've seen, you cannot modify immutables (string is an immutable(char)[]). If you actually do want the string to be modifiable, you should define it as char[] instead.

Then your example will work:

    void main()
    {
       char[] sMyText = "Replace the last char_";
       sMyText[$ - 1] = '.';
    }

If you actually want it to be immutable, you can still do it, but you can't modify in-place, you must create a new string that looks like what you want:

    void main()
    {
       string sMyText = "Replace the last char_";
       sMyText = sMyText[0 .. $-1] ~ ".";
       // you would do
       //sMyText[0 .. 5] ~ "." ~ sMyText[6..$];
       // to "replace" something in the 5th position
    }

Note that the second method allocates and uses the GC more (which is perfectly fine, but not something you want to do in a tight loop). For most circumstances, the second method is good.
May 19, 2014
On Sunday, 18 May 2014 at 19:09:52 UTC, Chris Cain wrote:
> On Sunday, 18 May 2014 at 18:55:59 UTC, Tim wrote:
>> Hi everyone,
>>
>> is there any chance to modify a char in a string like:
>
> As you've seen, you cannot modify immutables (string is an immutable(char)[]). If you actually do want the string to be modifiable, you should define it as char[] instead.
>
> Then your example will work:
>
>     void main()
>     {
>        char[] sMyText = "Replace the last char_";
>        sMyText[$ - 1] = '.';
>     }
>
> If you actually want it to be immutable, you can still do it, but you can't modify in-place, you must create a new string that looks like what you want:
>
>     void main()
>     {
>        string sMyText = "Replace the last char_";
>        sMyText = sMyText[0 .. $-1] ~ ".";
>        // you would do
>        //sMyText[0 .. 5] ~ "." ~ sMyText[6..$];
>        // to "replace" something in the 5th position
>     }
>
> Note that the second method allocates and uses the GC more (which is perfectly fine, but not something you want to do in a tight loop). For most circumstances, the second method is good.

Thanks - I already tried:

     void main()
     {
        char[] sMyText = "Replace the last char_";
        sMyText[$ - 1] = '.';
     }

but I always getting "Error: cannot implicitly convert expression ("Replace the last char_") of type string to char[]". I know, I can use cast(char[]) but I don't like casts for such simple things...
May 19, 2014
On 05/19/2014 10:07 AM, Tim wrote:

> I already tried:
>
>       void main()
>       {
>          char[] sMyText = "Replace the last char_";
>          sMyText[$ - 1] = '.';
>       }
>
> but I always getting "Error: cannot implicitly convert expression
> ("Replace the last char_") of type string to char[]".

That's a good thing because that string literal is immutable. If that code compiled you would get undefined behavior.

> I know, I can use cast(char[])

Unfortunately, not in this case. That undefined behavior would manifest itself as a "Segmentation fault" on many systems. :)

> but I don't like casts for such simple things...

What you want to do makes sense only if you have a mutable ASCII string. Such strings are generated at run time so the problem is usually a non issue:

import std.stdio;

void main()
{
    foreach (line; stdin.byLine) {
        char[] s = line.dup;    // (or .idup if you want immutable)
        s[$-1] = '.';
        writefln("Input : %s", line);
        writefln("Output: %s", s);
    }
}

Ali