SCASB compares AL with the byte at ES:DI: it sets the flags as CMP AL, ES:[DI] would (AL minus the memory byte), then moves DI by +1 (DF = 0) or -1 (DF = 1). SCASW compares AX with a word and steps by 2. SI is not used, and the string is only read. The operand is always at ES:DI; there is no segment override, so in an .EXE make sure ES points at the string's segment.

Searching

REPNE SCASB scans until it finds AL or CX runs out. Afterwards ZF = 1 means found and ZF = 0 means not found (again, test ZF and not CX: a match in the last position leaves CX = 0 too). DI points one past the match, so its 0-based index is DI - start - 1. N - CX is how many bytes were examined, the match included.

REPE SCASB does the reverse: it skips while the bytes equal AL, for example to skip leading spaces with AL = ' '. When it stops on a different byte, that byte is at DI - 1.

String length

The classic strlen of a 0-terminated string: AL = 0, CX = 0FFFFh as "no limit", REPNE SCASB. Each byte scanned, the 0 included, takes one off CX, so NOT CX gives the count scanned and one DEC CX removes the 0.

CLD
MOV DI, OFFSET TXT1
XOR AL, AL ; look for the 0
MOV CX, 0FFFFh ; no limit
REPNE SCASB
NOT CX ; bytes scanned, the 0 included
DEC CX ; the length: 8
MOV AL, CL
ADD AL, '0' ; digit -> character
MOV DL, AL
MOV AH, 02h ; DOS: print DL
INT 21h
TXT1 DB 'assembly', 0

Pitfalls

Forgetting CLD, or forgetting ES. Using SCASW to search bytes: it compares pairs of bytes at the current DI and steps by two, so it can skip right past a single byte. If CX starts at 0 nothing is compared and ZF keeps whatever value it had.