Chapter 7: HANDLING STRING DATA: STRING VARIABLES AND "SYMBOLS" 

Ferret offers a variety of tools for manipulating strings through the use of "symbols" (variables defined to be strings). In addition, beginning with Version 5.4, string variables are supported, with much the same syntax as for numeric variables. 


Ch7 Sec1.  STRING VARIABLES 

String variables are defined using DEFINE VARIABLE (or its alias LET). They can be read from and written to netCDF files. Arrays of strings may be defined and a limited number of algebraic operations are defined for string variables. They can be passed to go scripts and functions. Grave accents around a scalar string return the string. 

yes? LET astring = "hello everyone"
yes? LIST/NOHEAD astring
       "hello everyone"
yes? message `astring`
!-> message hello everyone
hello everyone
 Hit Carriage Return to continue 



Ch7 Sec1.1.  String arrays 

Strings in arrays may be of variable length. The syntax {"a","b","c"} denotes an array of strings. Two commas in a row denotes a null (missing value) string. Single and double quoted strings are both allowed, but must match for an individual string, e.g. 'P" is not valid. 

Examples:  the following define and list valid string arrays: 

yes? LET a =  {"s1","s2", ,"s3"}

yes? LIST a
            {"s1","s2", ,"s3"} 

 1   / 1:"s1"
2   / 2:"s2"
3   / 3:""  
4   / 4:"s3"

yes? LET b = {, 'string1','s2',,'cccc'}
yes? LIST/i=3:5 b
            {, 'string1','s2',,'cccc'}
3   / 3:"s2"
4   / 4:""       
5   / 5:"cccc"  

yes? LET c = {'p', 'q', 'a longer string'}
yes? LIST/NOHEAD/ORDER=x c
       "p"            "q"            "a longer string" 




Ch7 Sec2.  STRING FUNCTIONS 

A number of functions are available for working with string variables. They are described in the following sections. See also the section later in this chapter, "PLOT+ string editing tools" (p. 240) for more ways to manipulate 


Ch7 Sec2.1.  STRCMP(string1, string2) 

string1: string
string2: string
result: real 

Compares two strings or string arrays.  It computes the numerical difference in ASCII character value for the first character that differs between the two strings returns  a number, > 0 if string1 > string2, 0 if they are equal and < 0 if string1 < string2. 

Examples: 

yes? list strcmp("b",{"a","b","c"})
            VARIABLE : STRCMP("b",{"a","b","c"})
            SUBSET   : 3 points (X)
1   / 1:  1.000
2   / 2:  0.000
3   / 3: -1.000

yes? list strcmp({"a","b","c"},YSEQUENCE({"a","b","c"}))
            VARIABLE : STRCMP({"a","b","c"},YSEQUENCE({"a","b","c"}))
            SUBSET   : 3 by 3 points (X-Y)
            1      2      3    
            1      2      3
1   / 1:  0.000  1.000  2.000
2   / 2: -1.000  0.000  1.000
3   / 3: -2.000 -1.000  0.000

yes? let a = "a longer string"
yes? list strcmp (a,"a longer stringg")
            VARIABLE : STRCMP (a,"a longer stringg")
        -103.0 



Ch7 Sec2.2.  STRLEN(string1) 

string1: string
result: real 

Returns the length of the string passed in string string1 


Ch7 Sec2.3.  UPCASE(string1) 

string1: string
result: string 

Returns the string passed in string string1 in all upper case characters  


Ch7 Sec2.4.  DNCASE(string1) 

string1: string
result: string 

Returns the string passed in string string1 in all lower case characters  


Ch7 Sec2.5.  STRINDEX(string1, substring) 

string1: string
substring: string
result: real 

Locate first occurrence of  substring in  string1. Returns a 0 if substring doesn't exist in string1. If substring contains a zero-character string (i.e. ""), the function returns 1. 


Ch7 Sec2.6.  STRRINDEX(string1, substring) 

string1: string
substring: string
result: real 

Locates last occurence of string substring in string1. Returns a 0 if substring doesn't exist in string1. If substring contains a zero character string (i.e. ""), the function returns the length of string1 


Ch7 Sec2.7.  SUBSTRING(string1, offset, len) 

string1: string
offset: integer
len: integer
result: string 

Returns substring of length len from string string1 beginning from character offset in string1. If offset is 0, or if offset is greater than the length of string string1, a NULL value is returned. If length len exceeds the total length of string string1, the value of string string1 starting at offset is returned. 


Ch7 Sec2.8.  STRCAT(string1, str2) 

string1: string
string2: string
result: string 

Append a copy of  string string2 onto string string1. 


Ch7 Sec2.9.  STRFLOAT(string1) 

string1: string
result: real 

Return float value of string string1 (e.g. STRFLOAT("3.14")) 


Ch7 Sec2.10.  LABWID(string, charsize) 

string: string, possibly including a font specification, and may include <NL> newline character
charsize: real

result: real 

Returns the size in plot-page inches of the string. If a font is specified, it takes the size of characters in that font into account. If the string is a multi-line label, the result is computed for the longest line as it will appear on the plot page. 

Examples: 

        ! LABWID with two different character sizes,
       ! lowercase vs capitals, and the italics font

 yes?  LIST/NOHEADER  LABWID("abcdefg", .15)
         0.8857
  yes? LIST/NOHEADER  LABWID("abcdefg", .10)
         0.5905
  yes? LIST/NOHEADER  LABWID("ABCDEFG", .15)
         0.9929
 yes?  LIST/NOHEADER  LABWID("@IIabcdefg", .15)
         1.0000


       ! multi-line label: result is the length of the longest line
  yes? LIST/NOHEADER  LABWID("abcdefg<NL>hi", .15)
         0.8857

       ! Make a plot, drawing one label after another.
       ! Use the italics font for the first label.

  yes? PLOT/VS/LINE/I=1:314 i*cos(i/20),i*sin(i/20)

  yes? LET firstlab = "@iiMy label"
  yes? LABEL/NOUSER 0, 3, -1, 0, .15, "`firstlab`"
  yes? LET wid = labwid("`firstlab`", .15)
  yes? LABEL/NOUSER `wid`, 3, -1, 0, .15,  "@P4Second Label" 



Ch7 Sec2.11.  SPAWN command 

The SPAWN command executes a Unix system command and returns the result in a string array. The syntax SPAWN:"command" inside a string array definition allows the output of a Unix command to be mixed with other strings. 

Examples: 

LET a = {"first.nc", SPAWN:"ls *.nc","last.nc"} 

Say we want to check whether a file is in the directory. We do not want a null result, so start with a dummy string. If "myfile.nc" exists, there will be 2 entries in array a. 

yes? LET a = {"dummy", SPAWN:"ls myfile.nc"} 

yes? LET nfiles = `a,RETURN=IEND` 


yes? IF `nfiles EQ 2` THEN ... 



Ch7 Sec2.12.  Algebraic operations with string  variables. 

A number of algebraic operations are available for string variables. They are described in the following sections. 


Ch7 Sec2.12.1.  Logical operators with strings 

The operators EQ, LT, LE, ... can be applied to string variables and arrays. These operators are case-insensitive (functions will be provided later that are case-sensitive and include UPCASE, DNCASE) 

Examples: 

yes? LIST/NOHEAD {"a","b","c"} EQ {"A","B","C"} ! case insensitive
1   / 1:  1.000
2   / 2:  1.000
3   / 3:  1.000 

yes? LIST/NOHEAD"b" GT {"a","b","c"}
1   / 1:  1.000
2   / 2:  0.000
3   / 3:  0.000 



Ch7 Sec2.12.2.  Shift transformation of string arrays 

The shift transformation can be applied to string arrays. 

For example: 

yes? LET a = {"a","b","c","d"}
yes? LIST a[i=@SHF]
            {"a","b","c","d"}
            shifted by 1 pts on X
1   / 1:"b"
2   / 2:"c"
3   / 3:"d"
4   / 4:""
yes? LIST a[i=@SHF:-1]
           {"a","b","c","d"}
            shifted by -1 pts on X
1   / 1:""
2   / 2:"a"
3   / 3:"b"
4   / 4:"c" 



Ch7 Sec2.12.3.  Strings in IF-THEN-ELSE 

IF cond THEN string_array1 ELSE string_array2 

Example: 

yes? LIST/NOHEAD IF {0,1} THEN "hello" ELSE "goodbye"
1   / 1:"goodbye"
2   / 2:"hello" 



Ch7 Sec2.12.4.  String concatenation with "+": 

Examples: 

yes? let a = "good" + "bye" 

yes? LIST/NOHEAD YSEQUENCE({"now","then"})+", " + (if {0,1} THEN "hello"+", ") + "friend"
1   / 1:"now, friend"        "now, hello, friend"
2   / 2:"then, friend"       "then, hello, friend" 



Ch7 Sec2.12.5.  Strings as Function arguments 

A few functions also take strings as arguments. String arguments must be enclosed in double quotes. For example, a function to write variable "u" into a file named "my_output.v5d", formatted for the Vis5D program might be implemented as 

LOAD WRITE_VIS5D("my_output.v5d", a) 

SAMPLE* functions may take string or numerical arrays as arguments 

 Example: 

yes? LIST/NOHEAD  SAMPLEI({"a","b","c","d","e","f"},{3,2,,1})
1   / 1:"c"
2   / 2:"b"
3   / 3:""
4   / 4:"a" 

yes? LIST/NOHEAD  SAMPLEJ(YSEQUENCE ({"a","b","c","d","e","f"}), {3,2,,1})
1   / 1:"c"
2   / 2:"b"
3   / 3:""
4   / 4:"a" 



Ch7 Sec2.12.6.  Regridding string arrays 

The regridding transformations @ASN, @XACT, @NRST can be used with character data. 

Examples: 

yes? LET a = {spawn:"ls *.nc"}
yes? LIST a
            {SPAWN:"ls *.nc"}
1   / 1:"d1.nc"
2   / 2:"d2.nc"
3   / 3:"d3.nc"
4   / 4:"d4.nc"
5   / 5:"d5.nc"
6   / 6:"d6.nc"
7   / 7:"d7.nc"

yes? DEFINE AXIS/X=0.1:0.7:.1 xasn
yes? LIST a[gx=xasn@ASN]
            {SPAWN:"ls *.nc"}
            regrid: 0.1 delta on X@ASN
0.1   / 1:"d1.nc"
0.2   / 2:"d2.nc"
0.3   / 3:"d3.nc"
0.4   / 4:"d4.nc"
0.5   / 5:"d5.nc"
0.6   / 6:"d6.nc"
0.7   / 7:"d7.nc"

yes? DEFINE AXIS/X=1:6:.5 xxact
yes: LIST a[gx=xxact@XACT]
            {SPAWN:"ls *.nc"}
            regrid: 0.5 delta on X@XACT
1    /  1:"d1.nc"
1.5  /  2:""     
2    /  3:"d2.nc"
2.5  /  4:""     
3    /  5:"d3.nc"
3.5  /  6:""     
4    /  7:"d4.nc"
4.5  /  8:""     
5    /  9:"d5.nc"
5.5  / 10:""     
6    / 11:"d6.nc"

yes? DEFINE AXIS/X=1:6:.4 xnrst
yes? LIST a[gx=xnrst@NRST]
            {SPAWN:"ls *.nc"}
            regrid: 0.4 delta on X@NRST
1    /  1:"d1.nc"
1.4  /  2:"d1.nc"
1.8  /  3:"d2.nc"
2.2  /  4:"d2.nc"
2.6  /  5:"d3.nc"
3    /  6:"d3.nc"
3.4  /  7:"d3.nc"
3.8  /  8:"d4.nc"
4.2  /  9:"d4.nc"
4.6  / 10:"d5.nc"
5    / 11:"d5.nc"
5.4  / 12:"d5.nc"
5.8  / 13:"d6.nc"
6.2  / 14:"d6.nc" 



Ch7 Sec2.13.  NetCDF input and output of string data 

String variables can be input and output to netCDF files. In the file the string axis is the fastest moving dimension and all strings are the same length (equal to the maximum length of the strings being written). Extra character spaces are padded with nulls. If  variable length strings are written out, then when read back they will again be variable length. 

Example: 

yes? SAVE/CLOBBER/FILE=test_string.cdf/HEADING=enhanced a[i=2:4] 



Ch7 Sec3.  SYMBOL COMMANDS 

The following are the relevant commands: 

DEFINE SYMBOL 

    usage: 

        DEFINE SYMBOL symbol_name = string 


SHOW SYMBOL 

    usage: 

        SHOW SYMBOL/ALL 

        SHOW SYMBOL symbol_name 

        SHOW SYMBOL partial_name 


CANCEL SYMBOL 

    usage: 

        CANCEL SYMBOL/ALL 

        CANCEL SYMBOL symbol_name 

Legal symbol names must begin with a letter and contain only letters, digits, underscores, and dollar signs. 

To invoke symbol substitution—the replacement of the symbol name with its (text) value—within a Ferret command include the name of the symbol preceded by a dollar sign in parentheses. 

For example, 

yes? DEFINE SYMBOL hi = hello everyone
yes? MESSAGE ($hi)              ! issues "hello everyone" msg 

It is also possible to nest symbol definitions, as the following commands illustrate: 

yes? DEFINE SYMBOL label_2 = My test label
yes? DEFINE SYMBOL number = 2
yes? SAY ($label_($number))
    My test label 



Ch7 Sec4.  AUTOMATICALLY GENERATED SYMBOLS 

A number of useful symbols are automatically defined whenever Ferret sets up a plot. Following any plotting command issue the command SHOW SYMBOLS/ALL to see a list. Consult the PLOT PLUS for Ferret Users Guide (section "General Global Symbols") for detailed  descriptions of the plot symbols. For example, if we wish to place a label “hello” at the upper right corner of a plot we might do the following 

yes? PLOT/I=1:100 SIN(I/6)
yes? LABEL/NOUSER ($ppl$xlen) ($ppl$ylen) 1 0 .2 hello 

This labeling procedure would work regardless of the aspect ratio of  the plot. Use the command SHOW SYMBOL/ALL to see the symbols (and see "General Global Symbols" in the PLOT+ Users Guide). 


Ch7 Sec5.  USE WITH EMBEDDED EXPRESSIONS 

When used together with Ferret embedded expressions symbols can be used to perform arithmetic on the plot geometry. For example, this command will locate the plot title in bold at the center of a plot regardless of the aspect ratio: 

yes? LABEL/NOUSER `($ppl$xlen)/2` `($ppl$ylen)/2` 0 0 .2 @AC($labtit) 



Ch7 Sec6.  ORDER OF STRING SUBSTITUTIONS 

The above example illustrates that the order in which Ferret performs string substitutions and evaluates immediate mode expressions in the command line is significant. The successful evaluation of the embedded expression `($ppl$xlen)/2` requires that ($ppl$xlen) is  evaluated before attempting the divide by 2 operation. The order of Ferret string substitutions is as follows: 

1.    substitute "GO" command arguments of the form "$1", "$2", ... 

2.    substitute symbols of the form ($symbol_name) (discussed here) 

3.    substitute command aliases 

4.    substitute immediate mode expressions. (But see example 3 below). 

Example 1 

If the script snoopy.jnl contains 

DEFINE SYMBOL fcn = $1
DEFINE ALIAS ANSWER LIST/NOHEAD/FORMAT=("Result is ",$2)
ANSWER `($fcn)(($3^2)/2)`+5 

then the command 

yes? GO snoopy EXP F5.2 2.25 

would evaluate to 

DEFINE SYMBOL fcn = EXP
DEFINE ALIAS ANSWER LIST/NOHEAD/FORMAT=("Result is ",F5.2)
LIST/NOHEAD/FORMAT=("Result is ",F5.2) `EXP((2.25^2)/2)`+5 

and would result in Ferret output of "Result is 17.57." 

Example 2 

We can use grave accent syntax and string variables to substitute the string into the command line. 

yes? LET my_reg =  "X=0:180,Y=-40:40,L=1"
yes? SHADE sst[`my_reg`] 

Example 3 

Immediate mode substitution of a string variable may be used to set the values of qualifiers. However the region qualifiers (/X=/Y=etc.) on a command are used to set the context for the grave accent expression. So Ferret parses command qualifiers before it parses grave accent expressions. Thus we can use this syntax to set a region: 

yes? let xreg = "40:180" 

yes? let yreg = "60S:42S" 

yes? set region/x=`xreg`/y=`yreg` 

But including the qualifier name in the string variable is NOT valid (the qualifier is parsed BEFORE the grave accent expression is substituted, so Ferret would issue the error that `my_region` is an unknown qualifier).  

yes? !THE FOLLOWING SYNTAX IS NOT VALID 

yes? LET my_region = "x=40:180/y=-60:-42"; set region/`my_region` 



Ch7 Sec7.  CUSTOMIZING THE POSITION AND STYLE OF PLOT LABELS 

All of the plot labels generated by Ferret are automatically defined as symbols. This includes the title ($labtit), X and Y axis labels ($labx),($laby), as well as the position labels (latitude, longitude, depth, time), which are normally placed at the upper left on a plot (see "Labels," p. 191). Sometimes it is desirable to change the location, size or fonts of these labels. The symbol facility makes it possible to do this in a way that is independent of the particular label strings or plot aspect ratio. See the demonstration script symbol_demo.jnl for an example. 


Ch7 Sec8.  USING SYMBOLS IN COMMAND FILES 

Often in Ferret command files the identical argument substitutions must  be repeated at several points in the file. Using symbols it is possible to write "cleaner" Ferret scripts in which the argument substitution occurs only once—to define a symbol which is used in place of the argument thereafter. See the demonstration script symbol_demo.jnl for an example. 


Ch7 Sec9.  PLOT+ STRING EDITING TOOLS 

The PLOT+ program provides a variety of tools for editing symbol strings. See the PLOT+ Users Guide for further information (p. 546). The special functions manipulate and reformat character strings. 

Note that many of these functions are handled directly by Ferret string functions such as STRINDEX, STRLEN, SUBSTRING, etc (p. 230). 

The general format is SET sym $function(arg1, arg2,...). The functions are: 

$EDIT(symbol,argument) 

Edit a symbol: change to uppercase, remove extra blanks, or remove all blanks 

$EXTRACT(start,length,symbol) 

Extracts selected characters  from  the  input string. 

$INTEGER(symbol) 

Converts a  number  to  integer  format 

$LENGTH(symbol) 

Returns the length of the input  string 

$LOCATE(substring,symbol) 

Locates a substring in the input string (compares only the first 30 characters of the substring.) 

$ELEMENT(position,delimiter,symbol) 

Extracts an element from an  input  string  in which  the  elements are separated by a specified delimiter. 

Example: 

yes? DEFINE SYMBOL test = my    string
yes? PPL SET upper_test $EDIT(test,COMPRESS)
yes? SHOW SYMBOL upper_test
UPPER_TEST = "my string" 



Ch7 Sec10.  SYMBOL EDITING 

Symbols may be edited and checked using the same controls that apply to journal file arguments. 

The section of this users guide entitled "Arguments to GO tools" (p 25) describes the syntax for checking and editing arguments. The identical syntax applies to symbols. As with the GO tool arguments (e.g., "$4"), all string manipulations are case insensitive. 

In brief, the capabilities include: 

default strings 

If a symbol is undefined a default value may be provided using the pattern ($my_symbol%my default string%). For example, 

($SHAPE%XY%) 

check against list of acceptable values 

A list of acceptable string values may be provided using the pattern
($my_symbol%|option 1|option 2|%). For example, 

($SHAPE%|X|Y|Z|T|%) 

will ensure that only 1-dimensional shapes (X, Y, Z, or T) are acceptable. 

string substitution 

Any of the optional string matches provided can invoke a substitution using the pattern ($my_symbol%|option 1>replacement|%). For example, 

($SHAPE%|X>I|Y>J|Z>K|T>L|%) 

will substitute I for X or J for Y, etc. 

Asterisk ("*") provides default substitution 

The asterisk character matches any string. For example, 

($SHAPE%|X|Y|Z|T|*>other%) 

will always result in "X," "Y," "Z," "T," or "other." 

Asterisk ("*") provides limited string editing 

The asterisk character, when used on the right hand side of a string substitution, inserts the original symbol contents 

($SHAPE%|*>The shape is *|%) 

error message control 

An error message can be provided if the symbol is undefined or doesn't match any options. The pattern for this is
($my_symbol%|option 1|option 2|<error message text %). For example, 

($SHAPE%|X|Y|Z|T|<Not a 1-dimensional shape%) 



Ch7 Sec11.  SPECIAL SYMBOLS 

PPLUS defines a number of global symbols which are available to the user.  They are documented in the PPLUS Users Guide, section 7.3, and listed in the chapter "Customizing Plots", section PPLUS special symbols (p.219 ). 

There are a few symbols, generated automatically by plots, which are not documented in the PLOT PLUS for Ferret Users Guide. Those are shown like all symbols by SHOW SYMBOLS, but cannot be redefined by the user. 

PPL$XPIXEL
PPL$YPIXEL 

the number of pixels in the horizontal (X) and vertical (Y) size of the current Ferret output window. Note: these are "0" if there is no current window -- hence they can be used as a test of whether there is an open window. 

BYTEORDER 

gives "BIG" or "LITTLE" according to endianness of the CPU 

FERRET_VERSION 

FERRET_PLATFORM 

give the Ferret version and the platform Ferret is running on. 

SESSION_DATE
SESSION_TIME 

gives the date and time when the current session began. 



For help with Ferret see our Support Policy