Remove Non-printable Characters From a String

This snippet demonstrates how to remove non-printable characters from an Igor string. This was prompted by a question in the forum. See the Working With Binary String Data Examples snippet for similar examples.

Igor Pro 9.00B08 introduced new features that make this process much faster, but the transformation can also be done using earlier versions of Igor. If your code only needs to run with Igor Pro 9, you only need the RemoveNonPrintableChars_IP9 function below. Otherwise I recommend that you include both functions and only directly call RemoveNonPrintableChars() so that when your code runs with Igor Pro 9 or later the faster function will automatically be used.

Function/S RemoveNonPrintableChars_IP8(String inStr)
    // Store the bytes of the string in a byte wave so we can
    // use wave related commands.
    Variable len = strlen(inStr)
    Make/FREE/B/U/N=(len) byteWave
    byteWave = char2num(inStr[p])
   
    // Set all non-printable characters to 0 (null)
    // The test below considers tab (9), line feed (10), and carriage return (13)
    // to be printable characters.
    MultiThread byteWave = (byteWave[p] >= 32 && byteWave[p] <= 126) || (byteWave[p] == 9 || byteWave[p] == 10 || byteWave[p] == 13) ? byteWave[p] : 0
   
    // Extract the non-null values from the wave. These are the printable characters.
    Extract/O/FREE/B/U byteWave, printableByteWave, byteWave[p] > 0
   
    // Convert the wave's data back to a string.
    Variable np = numpnts(printableByteWave)
    String outStr = ""
    outStr = PadString(outStr, np, 0)
    Variable n
    For (n=0; n < np; n++)
        outStr[n,n] = num2char(printableByteWave[n])
    EndFor
    return outStr
End

#if IgorVersion() >= 9
Function/S RemoveNonPrintableChars_IP9(String inStr)
    // Store the bytes of the string in a byte wave so we can
    // use wave related commands.
    WAVE/B/U byteWave = StringToUnsignedByteWave(inStr)
   
    // Set all non-printable characters to 0 (null)
    // The test below considers tab (9), line feed (10), and carriage return (13)
    // to be printable characters.
    MultiThread byteWave = (byteWave[p] >= 32 && byteWave[p] <= 126) || (byteWave[p] == 9 || byteWave[p] == 10 || byteWave[p] == 13) ? byteWave[p] : 0
    WaveTransform zapZeros, byteWave        // Remove all of the nulls from the wave
    String outStr = WaveDataToString(byteWave)  // Convert the bytes in the wave back into a string.
    return outStr
End
#endif  // IP9+

Function/S RemoveNonPrintableChars(String inStr)
#if IgorVersion() >= 9
    return RemoveNonPrintableChars_IP9(inStr)   // MUCH faster
#else
    return RemoveNonPrintableChars_IP8(inStr)
#endif
End

You can execute this test function to compare the performance between the IP8 and IP9 versions of the function.

Function testTime()
    Variable n
    Variable numTrials = 100
    Variable testStringLength = 1e5 // length of test string in bytes
   
    // Generate a test string that contains random bytes.
    String testString = ""
    testString = PadString(testString, testStringLength, 0)
    For (n=0; n < testStringLength; n++)
        testString[n,n] = num2char(trunc(abs(enoise(255))), 1)
    EndFor
   
    String outStr_IP8
    Variable aStart = StopMSTimer(-2)
    For (n=0; n < numTrials; n++)
        outStr_IP8 = RemoveNonPrintableChars_IP8(testString)
    EndFor
    Variable aStop = StopMSTimer(-2)
   
    Variable usingIP9OrLater = 0    // assume not using IP9 or later
#if IgorVersion() >= 9
    String outStr_IP9
    Variable bStart = StopMSTimer(-2)
    For (n=0; n < numTrials; n++)
        outStr_IP9 = RemoveNonPrintableChars_IP9(testString)
    EndFor
    Variable bStop = StopMSTimer(-2)
   
    // Make sure that the two methods give the same result.
    if (CmpStr(outStr_IP8, outStr_IP9, 2) == 0)
        print "The two methods give the exact same result."
    else
        print "WARNING: The two methods give different results."
    endif
   
    printf "RemoveNonPrintableChars_IP8: %g s   RemoveNonPrintableChars_IP9: %g s   %d trials.\r", (aStop-aStart)/1e6, (bStop-bStart)/1e6, numTrials
#else
    printf "RemoveNonPrintableChars_IP8: %g s %d trials.\r", (aStop-aStart)/1e6, numTrials
#endif
End

Here is what I get using Igor Pro 9.00B08:

•testTime()
  The two methods give the exact same result.
  RemoveNonPrintableChars_IP8: 3.93585 s   RemoveNonPrintableChars_IP9: 0.207991 s   100 trials.

 

Forum

Support

Gallery

Igor Pro 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More