| let, reset |
| join$, build$ |
| ucase$, lcase$, mcase$ |
| len, sizeof, varptr |
| asc, chr$ |
| left$, right$, remain$, extract$ |
| ltrim$, rtrim$, trim$ |
| space$, string$, nul$, repeat$ |
| val, str$, variant$ |
| parse, parse$, parsecount |
| hex$, oct$, bin$ |
| format$, using$, strreverse$ |
| ucode$, acode$, ucodepage |
| remove$, retain$, strdelete$ |
| regexpr, regrepl |
| strprt, varptr |
| mid$, instr, tally$, replace, |
| lset, rset, lset$, rset$, |
Unicode vs ANSI Strings
To address the issue that there are far more characters in the world's
languages than ASCII supported, a ISO character encoding scheme called
Unicode has been developed. It consists of over 100,000 characters
and uses more than 1 byte per character.
The most common scheme, UTF-8, incorporates the ASCII codes for the first 128 characters. It uses 1 byte each for the ASCII characters and up to 4 bytes for other characters.
Unicode has been adopted by both Windows and Unix-like operating systems for internal character encoding, in part because of its compatibility with legacy ASCII encoding.
ANSI continues to be PowerBASIC's default encoding scheme and it's string functions (such as UCase$, LCase, MCase$, ...) use ANSI encoding. However, PowerBASIC also supports Unicode encoding in two ways. It provides automatic translation to Unicode format for those API requiring Unicode character encoding (but only when string is contained within a variant data type). It also provides the ACode$ and UCode$ functions for converting between the two formats.
Search and Replace
One of the most common actions with strings is to find a string(s) - if
it exists and its position within another string. Once found, it is also
common to want to replace it, remove it, or insert something next to it.
PowerBASIC has several functions that satisfy these needs. The next list
groups the string functions into categories, with one-line descriptions
of the key features of the function.
Mid$ - once, at position Parse$ - once, nth occurrence Parse - all delimited sub-strings into array
Instr - first occurrence, specific string RegExpr - first occurrence, wildcard search pattern Verify - whether each character in list is found (T/F) Tally - number of occurrences (#)
Asc - replace a char once, at position Mid$ - replace a string once, at position RegRepl - replace a string once (wildcard search)
Replace - replace all occurrences of a string Tab$ - replace all occurrences of Chr(9) with spaces Remove$ - return all selected characters Retain$ - return all un-selected characters
StrInsert - insert string at location
Examples of each of these are found below in the reference section.
Str$, Format$, Using$
PowerBASIC provides three ways to return a string expression representing
a number - Str$ (least powerful), Format$(powerful) and Using$ (most
powerful).
Here's the basic syntax of all three.
result$ = Str$(number, digits%) 'numbers result$ = Format$(number, digits&, formatstring$) 'numbers result$ = Using$(mask$,expression) 'strings/numbers
And here some examples and comparisons of the three options. Str$ and Format$ are somewhat similar. The mask string formats are very different between Format$ and Using$.
result$ = Str$(number, digits%) 'syntax specified number of decimal digits but no trailing zeros rounds last digit leading space if number > 0 no leading space if zero leading - sign if number < 0
result$ = Format$(number, digits&, formatstring$) 'syntax supports triple mask (<0, 0, >0) and a single expression mask characters "" empty string 0 placeholder. digit or zero # digit, nothing, or user-specified character . decimal % write number as a percentage , display whole numbers with commas *x insert digit or character x E scientific notation " quoted string \x escape, literal character follows
result$ = Using$(mask$,expr,expr, ...) 'syntax multiple masks in a single string expression list of expressions, mix of string and/or numbers string mask chars ! 1st character & entire string \\ 1st two characters \ \ n spaces enclose, n+2 characters returned _ escape, literal character follows number mask chars # numeric digit . decimal point here , display whole numbers with commas $$ insert dollar sign *x replace leading blank spaces with x + insert plus sign - insert minus sign - escape, literal character follows
LEFT$, RIGHT$, REMAIN$, EXTRACT$
These function will truncate a string for you. With left$/right$, truncation
is from a specified position. With remain$/extract$, truncation is from
the location of a specified character. Extract$ returns left side characters
and remain$ returns right side characters. Both extract$ and remain$ start
searching from the left side of the string. Both also allow specification
of the starting position in the string.
a$ = "12345678" result$ = left$(a$,5) 'result$ = "12345" result$ = right$(a$,5) 'result$ = "45678" result$ = remain$(a$,"6") 'result$ = "78" result$ = remain$(a$, ANY "36") 'result$ = "78" result$ = extract$(a$,"6") 'result$ = "12345" result$ = extract$(a$, ANY "36") 'result$ = "12" result$ = remain$(7, a$,"6") 'result$ = "" not found, returns "" result$ = remain$(7, a$, ANY "36") 'result$ = "" not found, returns "" result$ = extract$(7, a$,"6") 'result$ = "78" result$ = extract$(7, a$, ANY "36") 'result$ = "78"
With extract$, if no match is found, all of the string is returned beginning with the starting position. With remain$, if no match is found, none of the string is returned.
CSET, CSET$, RSET, RSET$, LSET, LSET$
In general, these functions insert and justify (left/right/center) a shorter
string within a larger string.
With the Abs argument, the larger string content is unchanged except for the positions where the shorter string is inserted.
Without the Abs argument, the larger string content is replace with spaces, except for the positions where the shorter string is inserted. The Using argument allows specification of a replacement character other than a space.
The CSET/RSET/LSET functions put one string within another string, replacing the excess string with the selected padding character. The CSET$/RSET$/LSET$ pad one string with the selected padding character to reach a specific total length.
These actions are shown in the following examples. Note that the starting value of a$ is assumed in each example, rather than the result of a preceding example.
a$ = "222333444" ' 9-character string b$ = "---" CSet Abs a$ = b$ ' a$ = "222---444" 'original string + "---" RSet Abs a$ = b$ ' a$ = "222333---" 'original string + "---" LSet Abs a$ = b$ ' a$ = "---333444" 'original string + "---" CSet a$ = b$ ' a$ = " --- " 'insert string + spaces RSet a$ = b$ ' a$ = " ---" 'insert string + spaces LSet a$ = b$ ' a$ = "--- " 'insert string + spaces a$ = CSET$("xxx", 7) ' a$ = " xxx " 'pad char is space a$ = RSET$("xxx", 7) ' a$ = " xxx" 'pad char is space a$ = LSET$("xxx", 7) ' a$ = "xxx " 'pad char is space a$ = CSET$("xxx", 7 Using "*") ' a$ = "**xxx**" 'pad char is * a$ = RSET$("xxx", 7 Using "*") ' a$ = "****xxx" 'pad char is * a$ = LSET$("xxx", 7 Using "*") ' a$ = "xxx****" 'pad char is *
Note that the starting value of a$ is assumed in each example, rather than the result of a preceding example.
BIN$ / HEX$ / OCT$ Functions
PowerBASIC can work with numbers in other than base 10. In particular, it
supports base 2, 8, and 16. Numbers in bases other than 10 are written with
one of the following prefixes. Numbers in base 10 are referred to a decimal
values. Here's the notation to use for describing numbers of other bases. Note
that PowerBASIC supports 3 ways to represent octal notation.
&B - binary &O - octal (that's letter O, not number zero 0) &Q - octal &Q7 & - octal &7 &H - hexadecimal A = &H0F 'hex value of "0F" (decimal 15) B = &Q7 'octal value of "7" (decimal 7) C = &B11 'binary value of "11" (decimal 3)
To convert numeric values to strings, PowerBASIC supplies the BIN$, OCT$, and HEX$ functions. These three functions take a numeric value and return the binary (base 2), octagonal (base 8), or hexadecimal (base 16) value as a string.
To convert base 2/8/16 strings to numeric (base 10) numbers, use the VAL function. It recognizes the following base number string prefixes.
Regular Expressions
All of the PowerBASIC functions which let you find one string within
another string require that you explicitly specify the string being searched,
or in some cases specify a range of characters. All, that is, except for
the regular expression functions.
In addition to searching for specific strings, Regular Expression functions can search for strings which match patterns. The familar "*.txt" notation for listing files in dialogs is an example of a string pattern. The * is a pattern which stands for any combination of letters.
Regular expressions work in the same way, but with far more pattern options. Patterns can be made up of regular string characters but derive their power from the use of metacharacters. Metacharacters are characters which refer to a pattern, much like the * in the previous example or the characters in format$ or using$ formatting strings. The term "Regular Expressions" refers to the patterns that are defined for the search. Here are the metacharacters supported by PowerBASIC:
. period - any character ? question mark - zero or one match ^ caret - beginning-of-line + plus sign - one or more match $ dollar - end-of-line * asterisk - zero or more matches | stile - OR operator
[] characters to match [-] range of characters to match [^] exception matching
() match sub-pattern and remember the match
\ backslash literal \f Chr$(12) ff \s shortest match string \b word boundary \n Chr$(10) lf \t Chr$(9) tab \c case-sensitive \q Chr$(34) " \v Chr$(11) vtab \e Chr$(27) esc \r Chr$(13) cr \x** Chr$(&Hxx) Hex
Regular Expressions are an extremely powerful tool for search/replace operations. Many useful patterns are very simple but for more complicated search and replace demands, a regular expression can be fairly complicated and can be difficult to debug.
See the PowerBASIC Help file for more information on searching and replacing capabilities of regular expressions. Also, regular expressions are widely used, so you'll be able to find a ton of information on the Internet.
ASCII Character Codes
PowerBASIC supports the ASCII character encoding scheme, covering 128
characters stored as 8 bits (1 byte) per character. The ASCII
standard was released in 1963 and is now under control of the American
National Standards Institute(ANSI).
The PowerBASIC ASC function returns the ASCII decimal code for characters, whereas the PowerBASIC CHR$ function returns the character corresponding to a specified ASCII code.
ASCII characters and encoding values are shown in both hexadecimal and decimal format in the following table.
Char Dec Hex Chr Dec Hex Chr Dec Hex Chr Dec Hex ------------- ------------ ----------- ----------- (nul) 0 00 (sp) 32 20 @ 64 40 ` 96 60 (soh) 1 01 ! 33 21 A 65 41 a 97 61 (stx) 2 02 " 34 22 B 66 42 b 98 62 (etx) 3 03 # 35 23 C 67 43 c 99 63 (eot) 4 04 $ 36 24 D 68 44 d 100 64 (enq) 5 05 % 37 25 E 69 45 e 101 65 (ack) 6 06 & 38 26 F 70 46 f 102 66 (bel) 7 07 ' 39 27 G 71 47 g 103 67 (bs) 8 08 ( 40 28 H 72 48 h 104 68 (ht) 9 09 ) 41 29 I 73 49 i 105 69 (nl) 10 0a * 42 2a J 74 4a j 106 6a (vt) 11 0b + 43 2b K 75 4b k 107 6b (np) 12 0c , 44 2c L 76 4c l 108 6c (cr) 13 0d - 45 2d M 77 4d m 109 6d (so) 14 0e . 46 2e N 78 4e n 110 6e (si) 15 0f / 47 2f O 79 4f o 111 6f (dle) 16 10 0 48 30 P 80 50 p 112 70 (dc1) 17 11 1 49 31 Q 81 51 q 113 71 (dc2) 18 12 2 50 32 R 82 52 r 114 72 (dc3) 19 13 3 51 33 S 83 53 s 115 73 (dc4) 20 14 4 52 34 T 84 54 t 116 74 (nak) 21 15 5 53 35 U 85 55 u 117 75 (syn) 22 16 6 54 36 V 86 56 v 118 76 (etb) 23 17 7 55 37 W 87 57 w 119 77 (can) 24 18 8 56 38 X 88 58 x 120 78 (em) 25 19 9 57 39 Y 89 59 y 121 79 (sub) 26 1a : 58 3a Z 90 5a z 122 7a (esc) 27 1b ; 59 3b [ 91 5b { 123 7b (fs) 28 1c < 60 3c \ 92 5c | 124 7c (gs) 29 1d = 61 3d ] 93 5d } 125 7d (rs) 30 1e > 62 3e ^ 94 5e ~ 126 7e (us) 31 1f ? 63 3f _ 95 5f del 127 7f
String Function Listing
Here's a simple listing of the string functions above, with a one-line
description of what the function does. Syntax and examples are given
in the next section.
String Functions Reference
Here are examples for each of the string functions. The
functions are listed in alphabetical order.
result = ASC("dog",1) ' result = 100 "d" is ASCII 100 result = ASC("dog",3) ' result = 103 "g" is ASCII 103 result = ASC("dog") ' result = 100 1st char is default result = ASC("dog", -2) ' result = 111 -2 counts backwards a$ = "dog" ASC(a$,2) = 104 ' a$ = "dhg" ASCII 104 is "h"
When used to get an ASCII value, if a null (zero-length) is passed, the position is zero, or the position is greater than the length of the string, -1 is returned.
When used to replace a value, a null string/zero position/long position causes the operation to fail (replacement not made).
a$ = "t" + nul$(1) + "o" + nul$(1) ' a$ = "to" 4 byte Unicode a$ = ACode$(a$) ' a$ = "to" 2 byte ASCII
result$ = bin$(6) ' result$ = "110"
result$ = Build$(x$,y$,z$) ' same as result$ = x$+y$+z$
Works only with dynamic strings (variables or literals) or string equates.
result$ = Chr$(65) ' result$ = "A" result$ = Chr$(65,66) ' result$ = "AB result$ = Chr$(65 TO 68) ' result$ = "ABCD" result$ = Chr$("1stLine",13,10,"2ndLine") ' 2-line result
Chr$() allows a list of codes, strings, or code ranges. Is especially useful for creating characters which are not easy to create using a keyboard.
a$ = "222333444" ' 9-character string b$ = "---" CSet Abs a$ = b$ ' a$ = "222---444" 'original string + "---" CSet a$ = b$ ' a$ = " --- " 'insert string + spaces a$ = CSET$("xxx", 7) ' a$ = " xxx " ' space pad a$ = CSET$("xxx", 7 Using "*") ' a$ = "**xxx**" ' * pad
a$ = "12345678" result$ = extract$(a$,"6") 'result$ = "12345" result$ = extract$(a$, ANY "36") 'result$ = "12" result$ = extract$(7, a$,"6") 'result$ = "78" result$ = extract$(7, a$, ANY "36") 'result$ = "78"
Syntax: Format$(number, digits& | formatstring$) 'numbers result$ = Format$(123.456, "#.##") 'result$="123.46" mask characters "" empty string 0 placeholder. digit or zero # digit, nothing, or user-specified character . decimal % write number as a percentage , display whole numbers with commas *x insert digit or character x E scientific notation " quoted string \x escape, literal character follows
result = instr("abc2b3", "b") 'result = 2 result = instr(3, "abc2b3", "b") 'result = 5, startpos=3 result = instr("abc2b3", ANY "2c") 'result = 3, match "2" or"c"INSTR is case-sensitive. If no match is found, 0 is returned. Position can be negative (starts from right). The starting position is optional (1 is assumed). When ANY is included, the match string is treated as a list of characters. When any character is matched, that position is returned.
Dim A(2) as String a(0)="5":a(1)="7":a(2)="3" result$ = join$(A(),"") 'result$ = "573" result$ = join$(A(),":") 'result$ = "5:7:3" result$ = join$(A(),""",""") 'result$ = "5", "7", "3"
result$ = LCase$("Dog") 'result$ = "dog"
a$ = "12345678" result$ = left$(a$,5) 'result$ = "12345"
a$ = "1234" result = Len(a$) 'result = 4
For fixed length string, returns the length of the buffer. For ASCIIZ strings, returns length of data stored (SizeOf returns maximum size of ASCIIZ string).
a$ = "222333444" ' 9-character string b$ = "---" LSet Abs a$ = b$ ' a$ = "---333444" 'original string + "---" LSet a$ = b$ ' a$ = "--- " 'insert string + spaces a$ = LSET$("xxx", 7) ' a$ = "xxx " ' space pad a$ = LSET$("xxx", 7 Using "*") ' a$ = "xxx****" ' * pad
result$ = LTrim$(" dog") 'result$ = "dog" result$ = LTrim$("abc123", "abc") 'result$ = "123" result$ = LTrim$("abc123", ANY "bca") 'result$ = "123"
When ANY is included, the removal string is treated as a list of characters. If any match the main string, that character is removed - until a character is reached in the mainstring which is not in the list.
a$="r": b$="s": c$="t" result$ = Max$(a$, b$, c$) 'result$ = "t"
String arguments are compared character by character, using the ASCII values to determine which is the largest character.
result$ = LCase$("DOG") 'result$ = "Dog" result$ = LCase$("BOB.DOG") 'result$ = "Bob.Dog"
The first letter of each word in the string is capitalized, where a word is a series of letters.
result$ = Mid$("abc123", 3, 2) 'result$ = "c1" pos=3 len=2 result$ = Mid$("abc123", -3, 2) 'result$ = "12" pos=-3 len=2 result$ = Mid$("abc123", 3) 'result$ = "c123" pos=-3 a$ = "abc123" mid$(a$,1) = "wxyz" ' a$ = "wxyz23" mid$(a$,1,2) = "wxyz" ' a$ = "--c123"
Negative position means position counting starts from right of string. Mid$ cannot increase the length of a string.
a$="r": b$="s": c$="t" result$ = Min$(a$, b$, c$) 'result$ = "r"
result$ =
result$ = Nul$(5) ' result$ has 5 Chr$(0) characters
a$ = "5,6,7" 'comma delimited parse a$, D$() 'D(0)="5" D(1)="6" D(2)="7" a$ = "5:6:7" 'colon delimited parse a$, D$(),":" 'D(0)="5" D(1)="6" D(2)="7" a$ = "5:6;7" 'two different delimiters parse a$, D$(), ANY ":;" 'D(0)="5" D(1)="6" D(2)="7"
When ANY is included, the delimiter string is treated as a list of characters. When any character is matched, a new array element is parsed.
a$ = "5,6,7" 'no delimeter assumes comma result$ = parse$ (a$,3) 'result$ = "7" a$ = "5:6;7" result$ = parse$ (a$,ANY ":;",2) 'result = "6"
Dimensioning the array to the correct size is recommended. Use ParseCount to get exact number of elements. Delimiters are case-sensitive. The selected field may be a negative number, meaning counting from right.
a$ = "5:6;7" result = ParseCount(a$) 'result = 3
Syntax: REGEXPR mask$ IN main$ [AT start&] TO iPos& [, iLen&] a$ = "You have 33 problems" b$ = "[0-9]+" 'one or matches of any numbers REGEXPR b$ IN a$ TO position&, length& amount$ = MID$(a$, position&, length&) 'amount$ = 33
Syntax: REGREPL a$ IN b$ WITH c$ [AT start&] TO iPos&, newmain$ a$ = "You have 33 problems" b$ = "[0-9]+" 'one or matches of any numbers REGREPL b$ IN a$ WITH "21" , d$ 'd$ = "You have 21 problems"
a$ = "12345678" result$ = remain$(a$,"6") 'result$ = "78" result$ = remain$(a$, ANY "36") 'result$ = "78" result$ = remain$(7, a$,"6") 'result$ = "" not found result$ = remain$(7, a$, ANY "36") 'result$ = "" not found
a$="12345654123" result$ = Remove$(a$, "345") 'result$ = "12654123" result$ = Remove$(a$, "23") 'result$ = "1456541" result$ = Remove$(a$, ANY "345") 'result$ = "12612"
Removes all occurrences of the matchstring. With ANY, removes all occurences of individual characters found within matchstring.
result$ = Repeat$(5,"x") 'result$ = "xxxxx" result$ = Repeat$(3,"a1") 'result$ = "a1a1a1"
a$="12345654123" Replace "23" WITH "--" IN a$ 'a$ = 1--456541--" a$="12345654132" Replace ANY "23" WITH "AB" IN a$ 'a$ = 1--456541--" a$="12345654132" Replace ANY "26" WITH "**" IN a$ 'a$ = 1--456541--"
Replaces all occurences.
a$ = "dog" Reset a$ ' a$ = "" Dim a$(1) a(0)="j": a(1)="k" Reset a$() 'a(0)="": a(1)=""
Applies to string array elements or entire array.
a$="12345654123" result$ = Retain$(a$, "23") result$ = Retain$(a$, ANY "136")
Returns empty string if match string is empty.
a$ = "12345678" result$ = right$(a$,5) 'result$ = "45678"
a$ = "222333444" ' 9-character string b$ = "---" RSet Abs a$ = b$ ' a$ = "222333---" 'original string + "---" RSet a$ = b$ ' a$ = " ---" 'insert string + spaces a$ = RSET$("xxx", 7) ' a$ = " xxx" ' space pad a$ = RSET$("xxx", 7 Using "*") ' a$ = "****xxx" ' * pad
result$ = RTrim$("dog ") 'result$ = "dog" result$ = RTrim$("abc123", "123") 'result$ = "abc" result$ = RTrim$("abc123", ANY "312") 'result$ = "abc"
a$ = "12345" result = SizeOf(a$) 'result = 5
For fixed-length, ASCIIZ and UDT string, returns the maximum size of the structure. For dynamic strings returns 4, which is the byte size of the handle. Use LEN to get the number of characters in a dynamic string.
See the PowerBASIC Help file for more details. SizeOf has several nuances that should be understood before using the function.
result$ = Space$(5) 'result$ = " "
Negative number of repeats is not allowed.
result$ = Str$(5.2) ' result$ = "5.2"
a$ = "1234567890" result$ = StrDelete$(a$, 1, 5) 'result$ = "67890" pos=1 len=5 result$ = StrDelete$(a$, 3, 4) 'result$ = "127890" pos=3 len=4
Does not support negative starting position values.
result$ = String$(5,"-") 'result$ = "-----" result$ = String$(3,"s") 'result$ = "sss"
Works on only 1 character. Use Repeat$ on multi-character strings.
a$ = "12345678" result$ = StrInsert$(a$, "--", 3) 'result$ = "12--345678"
Dim result as DWORD, a$ a$ = "5" result = StrPtr(a$) 'result is a 32-bit memory address
May not be used with fixed-length or ASCIIZ string (use VarPtr). Note that StrPtr returns address of the actual string content, whereas VarPtr returns the address of the string's handle.
When a dynamic string value is changed, so does the location of the string data, but not the location of the string handle.
Note that STRPTR may not return a valid pointer for empty strings ("").
a$ = "1234" result$ = StrReverse$(a$) 'result$ = "4321"
a$ = "dog": b$ = "cat" Swap a$, b$ ' a$="cat", b$="dog"
result$ = Tab$(a$, 20) 'replaces Tabs in a$ with variable 'spaces so resulting string data starts 'at tabstops every 20 columns.
a$="1234abcd5612" result = Tally(a$, "12") 'result = 2 result = Tally(a$, ANY "a51") 'result = 4
Tally is case-sensitive. Search string can be single or multiple characters. When ANY is included, the match string is treated as a list of characters. When any character occurs, the tally is incremented.
result$ = Trim$(" dog ") 'result$ = "dog" result$ = Trim$("abcdog ", ANY "abc ") 'result$ = "dog" result$ = Trim$("abcdog123", ANY "ba32") 'result$ = "cdog1"
result$ = LCase$("Dog") 'result$ = "DOG"
result$ = UCodePage 5 TO a&
Changes the codepage used by PowerBASIC, not by the computer. Previous codepage may be saved for re-use.
result$ = UCODE$("test") 'result$ is 8 bytes
Syntax: Using$(mask$,exp,exp,...) 'strings/numbers result$ = Using$("#.##", 123.456) 'result$ = "123.46" result$ = Using$("!","abc") 'result$ = "a" string mask chars ! 1st character & entire string \\ 1st two characters \ \ n spaces enclose, n+2 characters returned _ escape, literal character follows number mask chars # numeric digit . decimal point here , display whole numbers with commas $$ insert dollar sign *x replace leading blank spaces with x + insert plus sign - insert minus sign - escape, literal character follows
result = "52AR" ' result = 52 result = "1.0G4T" ' result = 1.04 result = "A22" ' result = 0 result = "2e2" ' result = 200 result$ = "&H2" ' result = 2 result$ = "&HB" ' result = 11
Notes: Leading white spaces are ignored. +/- symbols are allowed. "eEdD" may be used as powers of 10. Binary (&B) and octal (&O, &Q, &) strings are also recognized. Trailing type-specifiers are ignored.
Dim a as Variant a = "hello" result$ = Variant$(a) 'result = "hello"
Dim result as DWORD, a$ a$ = "5" result = VarPtr(a$) 'result is a 32-bit memory address
Cannot be used on register variables.
Note that StrPtr returns address of the actual string content, whereas VarPtr returns the address of the string's handle.
When a dynamic string value is changed, so does the location of the string data, but not the location of the string handle.
a$ = "0123456321" result$ = Verify(a$, "23") '
Returns zero is found, else position of first non-matching character. Is case-sensitive.
If you have any suggestions or corrections, please let me know.