Like I said, based on SubStr() and Decode():
Select
Decode(SubStr(TextField, 1, 1), '0', '0', '1', '1', '2', '2', '3', '3',
'4', '4', '5', '5', '6', '6', '7', '7', '8', '8', '9', '9', NULL) ||
Decode(SubStr(TextField, 2, 1), '0', '0', '1', '1', '2', '2', '3', '3',
'4', '4', '5', '5', '6', '6', '7', '7', '8', '8', '9', '9', NULL) ||
Decode(SubStr(TextField, 3, 1), '0', '0', '1', '1', '2', '2', '3', '3',
'4', '4', '5', '5', '6', '6', '7', '7', '8', '8', '9', '9', NULL) ||
Decode(SubStr(TextField, 4, 1), '0', '0', '1', '1', '2', '2', '3', '3',
'4', '4', '5', '5', '6', '6', '7', '7', '8', '8', '9', '9', NULL) ||
Decode(SubStr(TextField, 5, 1), '0', '0', '1', '1', '2', '2', '3', '3',
'4', '4', '5', '5', '6', '6', '7', '7', '8', '8', '9', '9', NULL) ||
Decode(SubStr(TextField, 6, 1), '0', '0', '1', '1', '2', '2', '3', '3',
'4', '4', '5', '5', '6', '6', '7', '7', '8', '8', '9', '9', NULL) ||
Decode(SubStr(TextField, 7, 1), '0', '0', '1', '1', '2', '2', '3', '3',
'4', '4', '5', '5', '6', '6', '7', '7', '8', '8', '9', '9', NULL) ||
Decode(SubStr(TextField, 8, 1), '0', '0', '1', '1', '2', '2', '3', '3',
'4', '4', '5', '5', '6', '6', '7', '7', '8', '8', '9', '9', NULL) ||
Decode(SubStr(TextField, 9, 1), '0', '0', '1', '1', '2', '2', '3', '3',
'4', '4', '5', '5', '6', '6', '7', '7', '8', '8', '9', '9', NULL) Num_Text
From Table;
As you can see, this kind of does the same thing as Translate() -- translate '1' to '1', '2' to '2', etc -- only, the "Otherwise" parameter(*) to Decode() guarantees that everything else gets translated into nothing at all. The key "magic" is the fact (? I certainly hope so!) that concatenating a string with NULL yields, not NULL, but the original string. The downside is, obviously, that we have to do it one character at a time. But, on the gripping hand: It works.
Now, this is based (and tested) on a nine-character "TextField"; if yours is longer, you just duplicate and adapt the long butt-ugly line(#) for each extra character; increment the second parameter to SubStr() (the bold red digits above) and keep concatenating each potentially-numeric result character to your total result. If yours is shorter, you delete a few lines from the end of the above, of course -- just remember to remove the "||" concatenation operator from the last one. The result of this operation will still be a string variable (i.e, of type VarChar2, presumably), albeit containing only numeric characters; if you want it as a genuine numeric one, then wrap the whole shebang in a call to the To_Num() function.
[Edit - forgot to add:] What I didn't test, is performance. If you recall the thread here about Decode() a little while ago, opinion about its use was divided; it can have a significant impact on performance sometimes; in other situations, it's negligible. Nothing for it but to try it out, I suspect... Oh, what the heck, I'll try it out forya! OK, results: Selecting, as per the above, the numerics of a VarChar2(10) field from a 208,000-row table took 4.1 seconds. This field, although defined as character, seems to contain only numbers. (I wrapped it in Max() and Min(), so as to eliminate 208,000 rows using up our bandwidth and scrolling up my screen; same reult both times.) Tried another field, VarChar2(30) (this one doesn't seem to contain any numerics at all), the same way; that took 15 seconds.
HTH!
(*): Very useful, that "default" parameter -- the rule-of-thumb to remember is, if the number of parameters to Decode() is even, then every source value not specified in the previous parameters stays as-is; if the number of parameters is odd, then every non-specified value gets translated into the last, "odd-man-out", parameter value.
(#): Each "conceptual" line is split into two "actual" lines above, so as to stave off horizontal scrolling in your browser; the "line" that you are supposed to duplicate is the text from "Decode(SubStr(" to "'9', NULL) ||".