19
$\begingroup$

If I enter a string (say, "abc") in a cell, and then switch to box representation (Shift+Ctrl+E or menu item Cell ► Show Expression), I see the following:

Cell[BoxData["\"\<abc\>\""], "Input",
 CellChangeTimes->{{3.662918813714031*^9, 3.6629188530623317`*^9}}]

I understand everything in this expression except the delimiters \< and \>. They look like escape sequences (e.g. \\, \") or like symbols used in string representation of boxes (e.g. \(, \!, \*, etc), but I could not find their description anywhere. I experimented a little, and it looks they are ignored within strings (for example StringLength["\<"] evaluates to 0) and rejected as an incorrect input elsewhere.

What do \< and \> mean inside of a string? For what purpose they are automatically added into the low-level representation of a cell? What are their use cases?


$Version 
"10.2.0 for Microsoft Windows (64-bit) (July 7, 2015)"
$\endgroup$
13
  • 1
    $\begingroup$ BoxData["\"\<a\>\""] === BoxData["\"a\""] $\endgroup$ Commented Jan 28, 2016 at 13:53
  • 3
    $\begingroup$ It was usefull until version 5.2. It is documented here $\endgroup$
    – andre314
    Commented Jan 28, 2016 at 16:59
  • 1
    $\begingroup$ Just curious if you are using Mathematica to automatically create notebooks with GenerateDocument or Low-Level Notebook Programming; since the internal mark-up isn't needed in these cases. $\endgroup$
    – Edmund
    Commented Apr 13, 2016 at 23:03
  • 3
    $\begingroup$ Possible duplicate of Undocumented Backslash-LessThan operator in strings? $\endgroup$ Commented Aug 20, 2016 at 11:19
  • 2
    $\begingroup$ Shouldn't the newer one be a duplicate of the older one? Or perhaps they should be merged? $\endgroup$
    – Michael E2
    Commented Aug 20, 2016 at 11:59

3 Answers 3

22
$\begingroup$

This syntax was deprecated in the version 6.0 era. According to the legacy documentation,

enter image description here

For example, in version 5.2, the following strings are interpreted differently

string1 = "first line
  second line"

string2 = "\<first line
  second line\>"

enter image description here

$\endgroup$
3
  • $\begingroup$ These delimiters are still significant in string literals in box representations of cells (toggled by Shift+Ctrl+E) in newer versions of Mathematica (in particular in Mathematica 11), but lost significance in regular string literals. See my answer. $\endgroup$ Commented Aug 20, 2016 at 18:57
  • $\begingroup$ ilian, how would you feel about Merging this question with (105018)? That action would move this answer to that Q&A. You would lose the Accept, unless Vladimir moves the Accept to your answer, but this would keep multiple answers in one place rather than spread between different questions. $\endgroup$
    – Mr.Wizard
    Commented Aug 21, 2016 at 8:35
  • 2
    $\begingroup$ @Mr.Wizard I agree of course. Actually my answer is not as good and I wouldn't have posted it if I had known of Vladimir's earlier answer at the time. $\endgroup$
    – ilian
    Commented Aug 21, 2016 at 14:32
11
$\begingroup$

Thanks to andre's comment (where this link is provided), I now see the effect of those delimiters (I tested it in Mathematica 11 and also some earlier versions). When I add 2 newlines to the box representation of the cell:

Cell[BoxData["\"\<a

bc\>\""], "Input",
 CellChangeTimes->{{3.662918813714031*^9, 3.6629188530623317`*^9}}]

and switch back using Shift+Ctrl+E, then the cell look like this:

"a

bc"

But if I remove those delimiters:

Cell[BoxData["\"a

bc\""], "Input",
 CellChangeTimes->{{3.662918813714031*^9, 3.6629188530623317`*^9}}]

and switch back, then the cell looks like this:

"a  bc"

It seems that the purpose of \<,\> is to delimit ranges within string literals in raw box representations of cells where newlines should be exactly preserved. It looks like they only have effect in that context and are ignored in normal input in newer versions of Mathematica. The legacy documentation suggests that in Mathematica 5 they were significant in all string literals.


Update: I found an old discussion on this topic: [1],[2],[3].

$\endgroup$
2
  • $\begingroup$ Yes that's right. On Mathematica 5, when you wrote a string on several lines (in normal editing), all the carriage-return were removed, except if the string began with "\< and ended with \>". Nowodays, \< and \> are unecessary (in normal editing). $\endgroup$
    – andre314
    Commented Jan 28, 2016 at 20:06
  • $\begingroup$ Thanks for the links to the information I was looking for ! $\endgroup$
    – andre314
    Commented Jan 29, 2016 at 14:08
10
$\begingroup$

Summary of the all available information

In the hoarier days space-like characters (spaces, newlines, tabs) inside strings were interpreted on input in an odd way: for example single newlines followed by spaces or tabs were converted to a single space. The \<\> syntax was introduced as a way to avoid this: between \< and \> the space-like characters are interpreted literally with the only exception to line-ending backslash whish escapes the newline. This syntax was standardized in the modern Mathematica notebook format (introduced in 1996).

The kernel simply ignores the \<\> delimiters on input and also when you Get or Import a notebook file:

FullForm@"\<1\n2\>"
"1\n2"
"\<\>" // StringLength
0

Note that FrontEnd doesn't remove them on normal input:

"\<\>";
InString[-1]
"RowBox[{\"\\\"\\\\<\\\\>\\\"\", \";\"}]"

Starting from version 6 the behavior of strings on normal input was changed and the \<\> syntax is no longer needed for preserving space-like characters. But for direct editing of the low-level box representation of cells in the special cell editing mode of the FrontEnd (which is toggled by pressing Shift+Ctrl+E) it is still necessary as Vladimir showed. These delimiters aren't needed however when you programmatically work with the low-level representation (and the kernel simply removes them anyway!).

These delimiters are also added automatically when you Export as "NB", but not added when you Export as "Package":

StringCases[ExportString["1\n2", "NB"], "Cell[" ~~ Shortest@__ ~~ "\"Input\"]"] // First //
  ImportString[#, "Text"] &

Cell["\<\
1
2\
\>", "Input"]

ExportString["1\n2", "Package"]

(* Created with the Wolfram Language : www.wolfram.com *)

"1\n2"

Despite this a Notebook exported as a "Package" can be correctly opened or imported as "NB" preserving space-like characters:

nb = ImportString[ExportString["1\n2", "NB"], "NB"];
ImportString[ExportString[nb, "Package"], "NB"] === nb
True
NotebookPut[nb];

screenshot


Further elaboration

Let us consider the example given by John Fultz (please copy the code exactly as written!):

CellPrint@Cell["abc\
         d"]
abc         d

It is easy to check that there are 9 spaces between abc and d in the printed cell (and so are before d in the code). But the newline and the backslash are absent because the backslash at the end of line simply escapes the newline.

After pressing Shift+Ctrl+E we can see the code of the printed cell:

Cell["abc         d",
 GeneratedCell->True,
 CellAutoOverwrite->True,
 CellChangeTimes->{3.680677305471143*^9}]

Now let us add a space after the backslash (it isn't visible, but it is there!):

CellPrint@Cell["abc\ 
         d"]
abc 
          d

Now we got our newline but the backslash is absent (the next space is present). I think that the absence of the backslash can be related to the series of bugs I discuss in this answer. The code of the printed cell:

Cell["\<\
abc 
         d\
\>",
 GeneratedCell->True,
 CellAutoOverwrite->True,
 CellChangeTimes->{3.6806776850508537`*^9}]

Note that similar things happen when we write \n instead of entering the newline:

CellPrint@Cell["abc\\n         d"]
CellPrint@Cell["abc\ \n         d"]
abc\n         d

abc 
          d

In the first case here the newline character \n is escaped by the backslash and is present in the output literally. In the second case the backslash is absent again but the space at the first line is preserved.


An old discussion on MathGroup

A closely related (but not identical) question was asked by user kj and answered by John Fultz in the official newsgroup in 2010, so I'll cite here both the question and the answer completely:

The question:

When I examine the source code of Mathematica notebooks, I often see Cell objects whose first argument is preceded by

"\<\

and followed by

\
\>"

E.g.

Cell["\<\
Yet another undocumented item.\
\>", "Text"...

What do these delimiters mean? And how do they differ from the TextData symbol? (The latter is also undocumented, but at least I've seen "cameo appearances" of it in the documentation.)

TIA!
~kj

The answer:

Cell[_String] is equivalent to Cell[TextData[{_String}]] as far as the front end is concerned. The former is just an abbreviation of the latter syntax, which is necessarily used when the contents are more complex (e.g., contain styles or buttons).

The \<\> business dates back to a hoarier day (in my opinion) in the design of strings in Mathematica. Once upon a time, Mathematica had an odd interpretation of newlines which I probably made more sense in the days of 80 character terminal usage. You'll have to forgive me...my memory is fuzzy here, and I don't have an old Mathematica text to double-check this from my current location...but I believe the issue was something like this...

"abc\
         d"

...with the newlines and spaces as shown, being equivalent to "abc d" (with just the single space). The \<\> business forced everything inside the string to really be interpreted literally, with backslash at the end of a line meaning to simply escape the newline, and do nothing special to leading spaces. Since the Mathematica notebook format generally wraps at about 70 characters, the non-literal interpretation would have made the representation of more than 70 consecutive spaces difficult.

The modern Mathematica notebook format (introduced in 1996) was always made to be interpreted properly as a Mathematica expression should you call Get[] on it from the kernel. So this syntax was standardized, and is still used today. Now, the kernel simply ignores the \<\> delimiters as you can see below:

In[1]:== StringLength["\<x\>"]

Out[1]== 1

Sincerely,

John Fultz
jfultz at wolfram.com
User Interface Group
Wolfram Research, Inc.

$\endgroup$
12
  • $\begingroup$ Alexey, how would you feel about me Merging this question with (105018)? That would move this answer to that Q&A. You would lose the Accept but probably gain visibility for the answer. $\endgroup$
    – Mr.Wizard
    Commented Aug 21, 2016 at 8:27
  • $\begingroup$ @Mr.Wizard Actually I'm against this but I think reasonable merging this question with (112550) where we have authoritative answer by ilian. The reason is to have all information in one place; the accepted answer in (105018) doesn't add anything to these answers. $\endgroup$ Commented Aug 21, 2016 at 10:09
  • $\begingroup$ Hm... I also asked ilian about merging. I think the community would best be served by having all three answers in the same place. Do you disagree? If not is there any reason to have them all under 112550 rather than 105018? Typically we favor older questions unless the newer one is far better written, and that does not seem to be the case here? $\endgroup$
    – Mr.Wizard
    Commented Aug 21, 2016 at 10:13
  • $\begingroup$ @Mr.Wizard I agree that we can merge all three questions. To my taste, this current question is the most clear and is general enough to have all answers under it. I have one question: what will happen with comments under the questions after merging? $\endgroup$ Commented Aug 21, 2016 at 10:18
  • 1
    $\begingroup$ @Mr.Wizard Ok, I agree. $\endgroup$ Commented Aug 22, 2016 at 6:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.