String.​prototype.​isWellFormed(): inspect the original before replacing lone surrogates

A replacement-looking glyph does not tell you whether the string contains U+FFFD or a lone surrogate. Inspect UTF-16 units first, then make any replacement a separate visible action rather than silently changing the source.

The bench shows D800 as malformed and actual FFFD as well formed. It also includes plain ABC, a valid emoji pair and an empty string. Preview replacement calls toWellFormed on the retained original and displays the new units separately. For D800, the proposed copy becomes FFFD while the original remains D800, making the data-changing step explicit.

Same-looking glyphs. Different UTF-16 units.
Same-looking glyphs. Different UTF-16 units.
Open the full example ↗

Look at code units, not only the drawing

Construct deliberate fixed samples in JavaScript: ABC, the emoji pair D83D DE04, lone high surrogate D800, actual replacement character FFFD and empty string. Iterate indexed charCodeAt values and show each as four hexadecimal digits. The emoji has two UTF-16 units but a valid pair. D800 has no partner. FFFD is an ordinary well-formed scalar value even though its visible symbol can resemble the rendering of malformed input. The unit list preserves the distinction the visual appearance alone cannot establish.

The method isWellFormed reports whether any lone surrogate exists. It does not mutate the original string. A false result can lead a data workflow to reject the record and request corrected source rather than replace anything. Keep the retained sample in memory so the inspection does not first round-trip through an encoding or transport that replaces malformed units. The bench uses fixed buttons instead of a general escape parser, avoiding confusion between six visible characters spelling backslash-u-D800 and one actual surrogate unit.

Preview replacement as its own result

toWellFormed returns a string with lone surrogates replaced by U+FFFD. It cannot recover the character someone intended. Show proposed text, units and well-formedness beside the original, with a clear action label. A reviewer should be able to compare original D800 and proposed FFFD after the operation. Selecting actual FFFD should show No lone surrogates without implying that a repair occurred, since that source was already well formed.

Changing samples clears the old proposed copy rather than leaving a repair from another source beside the current original. Reset returns to D800 with no replacement preview. The page uses safe text output for both strings and never treats structural validity as permission to insert text as HTML. If a method is unavailable, retain code-unit inspection and explain which operation could not run. Do not provide an unverified fallback and label its output as the absent native API's result.

Keep the validation claim narrow

ABC and the emoji pair are well formed. The empty string is also well formed, but a required field can still reject it. A well-formed name can be misspelled, contain an unwanted control character or identify the wrong account. This check answers a structural UTF-16 question rather than establishing accuracy, suitability, security or field completeness. It also differs from normalization, which concerns equivalent text representations; composing an accent sequence and replacing a lone surrogate change data for different reasons.

End with an explicit reject-or-replace decision for the relevant dataset. Keep the original units and proposed replacement available when discussing possible information loss. Do not equate similar drawings, or use a true result as a universal Valid input badge. The workbench supplies concrete native-method outputs for deliberately constructed strings, while the application's maintained import rule remains responsible for deciding whether replacement is acceptable and for preserving whatever original evidence its workflow requires.

Make your own working example

Build a UTF-16 inspection bench with fixed sample buttons only: ABC; emoji constructed from \uD83D\uDE04; lone high surrogate \uD800; actual replacement character \uFFFD; empty string. Start on D800. Preserve original sample in memory without encoding it through a transport that changes lone units. Do not use eval or a general escape parser.

Show original rendered text, unit count and indexed charCodeAt values as four-digit uppercase hex. Call isWellFormed; label true No lone surrogates and false Contains a lone surrogate, not universal valid input. Add Preview replacement copy calling toWellFormed, showing separate text/units/status without overwriting original. D800 becomes FFFD in the proposed copy; actual FFFD initially returns true. Emoji retains valid D83D DE04.

Changing sample clears the previous proposal. Reset restores D800 and no proposed copy. Keep Original and Proposed panels adjacent on wide screens and stacked on mobile. If either native method is missing, keep unit inspection and identify unavailable operation honestly. Explain replacement cannot recover intended text and empty well formed does not satisfy required-field rules. No file parser, storage, normalization or security-validation claim.

Use one self-contained HTML file with no remote dependency. Keep the initial sample, output, and labeled controls near the top. Use at least 16px text, strong contrast, visible focus, and a stacked layout at 360px without horizontal overflow. Use explicit type=button click handlers and explicit DOM selectors; do not depend on native form submission. Clear stale feedback when task inputs change. Render entered text safely. Keep practice data local to the current page; do not imply saving, sending, or production integration. Return only the finished HTML.

Decide whether the import should replace

Keep the import rule and retained-source policy explicit. In an HTML comparison, NOS allows eligible static explanations to be revised visually without asking AI to regenerate the page. Clarify the replacement decision while comparing the original units with the proposed copy, then update the maintained import code separately.

Keep reading