From 31ba5208c8b2e65af801d7c51688c006cb00382e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 3 Aug 2026 08:18:03 +0200 Subject: [PATCH] docs: qualify the operator>> stream positioning guarantee (#5343) operator>>'s notes state that it leaves the stream positioned right after the parsed value, so that concatenated JSON values can be read back to back. That does not hold when the value is a number: a number is only terminated by the character that follows it, and the lexer's unget() is simulated (it rewinds only the lexer's own bookkeeping), so that character stays consumed from the stream. Document the actual behaviour: the guarantee holds for all value types except numbers, which must be followed by whitespace. Also qualify the cross-reference on the JSON Lines page, which repeated the unqualified claim. Documentation only; the behaviour itself is tracked in #5340. Signed-off-by: Niels Lohmann --- docs/mkdocs/docs/api/operator_gtgt.md | 37 ++++++++++++++++--- .../docs/features/parsing/json_lines.md | 3 +- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/docs/mkdocs/docs/api/operator_gtgt.md b/docs/mkdocs/docs/api/operator_gtgt.md index e1d24d47f..a9ba17564 100644 --- a/docs/mkdocs/docs/api/operator_gtgt.md +++ b/docs/mkdocs/docs/api/operator_gtgt.md @@ -33,17 +33,44 @@ A UTF-8 byte order mark is silently ignored. Invalid Unicode escapes and unpaired surrogates in the input are reported as [`parse_error.101`](../home/exceptions.md#jsonexceptionparse_error101) with a detailed message. -`operator>>` parses exactly one JSON value and leaves the stream positioned right after it, so it can be called -repeatedly to read a sequence of concatenated JSON values from the same stream: +`operator>>` parses exactly one JSON value, so it can be called repeatedly to read a sequence of concatenated JSON +values from the same stream: ```cpp json j1, j2; -input >> j1; // parses the first value, stream now positioned right after it +input >> j1; // parses the first value input >> j2; // parses the next value ``` -Note this does **not** work for [JSON Lines](../features/parsing/json_lines.md) (newline-delimited JSON) input -- -see that page for why and for the recommended alternative. +!!! warning "A number must be followed by whitespace" + + A number is only terminated by the character that follows it. That character is read from the stream to detect the + end of the number, and it is **not** put back. When a value that is a number is immediately followed by the next + value, the first character of that next value is lost: + + ```cpp + std::istringstream input("1true"); + json j1, j2; + input >> j1; // j1 == 1 + input >> j2; // throws parse_error.101: the stream now starts at "rue" + ``` + + Separating the values with whitespace avoids this, because the character that is eaten is then the separator: + + ```cpp + std::istringstream input("1 true"); + json j1, j2; + input >> j1; // j1 == 1 + input >> j2; // j2 == true + ``` + + Only numbers are affected. Values ending in a self-delimiting character do not read past themselves, so + `truefalse`, `[1][2]`, `{"a":1}{"b":2}`, and `"a""b"` can be read back to back without a separator. + + This is tracked in [#5340](https://github.com/nlohmann/json/issues/5340). + +Note that reading concatenated values does **not** work for [JSON Lines](../features/parsing/json_lines.md) +(newline-delimited JSON) input -- see that page for why and for the recommended alternative. !!! warning "Deprecation" diff --git a/docs/mkdocs/docs/features/parsing/json_lines.md b/docs/mkdocs/docs/features/parsing/json_lines.md index cda6f37c7..fb1481819 100644 --- a/docs/mkdocs/docs/features/parsing/json_lines.md +++ b/docs/mkdocs/docs/features/parsing/json_lines.md @@ -49,4 +49,5 @@ JSON Lines input with more than one value is treated as invalid JSON by the [`pa with a JSON Lines input does not work, because the parser will try to parse one value after the last one. This is different from parsing a stream of *concatenated* (non-newline-delimited) JSON values, for which - `operator>>` does work -- see its [notes](../../api/operator_gtgt.md#notes) for details. + `operator>>` does work, provided that a value that is a number is followed by whitespace -- see its + [notes](../../api/operator_gtgt.md#notes) for details.