How do I extract the contents of a selected cell as plain text?

Assuming nb is your notebook object, then this will do what you want without touching the clipboard:

First[FrontEndExecute[
  FrontEnd`ExportPacket[NotebookSelection[nb], "InputText"]]]

Some notes about this solution:

  • It preserves evaluation semantics precisely, regardless of typesetting.
  • It does not dirty the clipboard
  • If you prefer to get the appearance as opposed to the evaluation semantics, you can use "PlainText" (for example, grids copy as tabular looking things as opposed to as lists)
  • I tested this in 8.0.1, but it might not work in earlier versions

This FE packet only supports a limited number of formats. The public formats include "GIF", "PPM", "EnhancedMetafile" (Windows), "PICT" (Mac) , "PostScript", "RTF", "PDF", and "SVG".

I should say that the first argument of ExportPacket can also be any Notebook, Cell, or Box expression. Also, a NotebookObject, in which case it'd convert the entire notebook rather than just the selection.

When the selection does not contain a full cell it is enough to work around by using the results of NotebookRead. E.g.:

First[FrontEndExecute[ FrontEnd`ExportPacket[BoxData @ NotebookRead[nb], "PPM"]]]

NOTE: This answer is provided for illustrative purposes only, since it shows some techniques of working with boxed data. While it illustrates how one could emulate the correct behavior in some cases, this code should NOT be used in practice (as a solution for this particular problem), because doing so may be both fragile and dangerous. Please read the discussion comments below the answer to get a more complete picture.

This is what usually works for me:

Button["Set x to selection", 
   x = 
    StringJoin@
        Cases[
          NotebookRead[SelectedNotebook[]] /. Cell[BoxData[data_], ___] :> data, 
          _String, 
          Infinity
        ]
 ]

In particular, I used similar code in my syntax highlighter generator, so I've tested that this works, on many examples (although, the code of the generator is perhaps not the best place to consult, if one wants to stay sane).

EDIT

Here is a code which is supposed to work also for non-text boxes (such as SqrtBox), but it is pretty ugly and may also be fragile, to the point that the clipboard solution seems much better.

Button["Set x to selection",
  x = 
      With[{tag = StringJoin[ ToString /@ {Unique["tag"], Unique[]}]},
        StringReplace[
            StringJoin@
               Cases[
                  NotebookRead[SelectedNotebook[]] /. Cell[BoxData[data_], ___] :>
                   (ToExpression[
                      (data /. "\n" :> tag),
                      StandardForm,
                      Function[dt, MakeBoxes[InputForm[dt]], HoldAll]
                    ] /. InterpretationBox[StyleBox[code_String, ___], ___] :> code
                   ),
                  _String, {0, Infinity}
               ], 
            tag :> "\n"
        ]
      ]
 ]

For cases when you only have code, you should be able to use the first version though.