Reverse a string

Is there a simple command to reverse a string?

String s1 = "hello"
String s2 = s1[(strlen(s1)-1) - p]

Does not work because p is only used for wave assignment. s1[4,0] doesn't work either as described in the help file. Is there a command to reverse a string that I'm missing or should just build the reversed string using a loop?

Here's an example of how to do this without a loop, though I wouldn't argue that this wins any simplicity contests:

Function test()
    String s1 = "hello"
    String s2 = ReverseString(s1)       // this works
    print s2
   
    s1 = "hellÖ"       // Note the umlaut on the last letter
    s2 = ReverseString(s1)
    print s2    // This is not what you expect
End

Function/S ReverseString(String inputStr)
    Variable len = strlen(inputStr)
    if (numtype(len) != 0 || len < 1)
        return ""
    endif
   
    Make/FREE/B/U/N=(len) byteWave
    MultiThread byteWave = char2num(inputStr[p])
    Reverse byteWave
    String reversedString
    wfprintf reversedString, "%c", byteWave
    return reversedString
End

 

Note that as the test() function shows, the ReverseString function will give you what you expect if the input string contains only ASCII characters, but if the input string contains any multibyte characters you probably won't get what you expect when you reverse, since the reverse is done at the level of the bytes and not at the level of the Unicode code point or grapheme. If you needed to support reversing of strings containing non-ASCII characters I think you could do so but it would require a lot of effort.

Just for kicks, here's another way to do it. I suspect that this method is slightly faster but it relies on undocumented behavior and therefore is prone to break. Also, it requires that the length of the string be limited to a certain number of bytes. That limit could be worked around, if necessary, by putting the guts of ReverseString2 into a loop and doing the conversion from and to a structure multiple times.

Function test2()
    String s1 = "hello"
    String s2 = ReverseString2(s1)      // this works
    print s2
   
    s1 = "hellÖ"       // Note the umlaut on the last letter
    s2 = ReverseString(s1)
    print s2    // This is not what you expect
End

Constant theStringSize = 400

Structure ReverseString2Struct
    char theString[theStringSize]
EndStructure

Function/S ReverseString2(String inputStr)
    Variable len = strlen(inputStr)
    if (numtype(len) != 0 || len < 1)
        return ""
    endif
   
    STRUCT ReverseString2Struct s
    s.theString = inputStr
    Make/FREE/B/U tempWave
    StructPut s, tempWave
    Reverse tempWave
    Rotate strlen(inputStr), tempWave
    StructGet s, tempWave
    return s.theString
End

 

Something like the following?

 

/// Reverse a string on a byte by byte basis
Function/S ReverseString(str)
    string str
   
    variable length
   
    length = strlen(str)
   
    if(length == 0)
        return str
    endif

    Make/FREE/T/N=(1, length) wv = str[length - 1 - q]

    wfprintf str, "%s", wv
   
    return str
End

 

In reply to by thomas_braun

thomas_braun wrote:

Something like the following?

 

/// Reverse a string on a byte by byte basis
Function/S ReverseString(str)
    string str
   
    variable length
   
    length = strlen(str)
   
    if(length == 0)
        return str
    endif

    Make/FREE/T/N=(1, length) wv = str[length - 1 - q]

    wfprintf str, "%s", wv
   
    return str
End

 

If you're going to do this with a text wave, you should change the Make command to /T=1. Otherwise Igor will allocate an std::string on the heap for each point in the wave, and that could get moderately expensive for a long string.

Thank you Thomas and Adam. That works great! My use case is for strings of pure ASCII and some of them might be quite long. The final function with Adam's modification works fine.