Serhii Melnikov
Serhii Melnikov

Reputation: 47

Determine if the string contains numeric characters. If there are, then display them on the screen

I don't understand why it doesn't work. I need to read the user's string and check if there are numbers, if so print them. I seem to have done this, but it won't work and I don't understand what's wrong...

enter image description here

word_digits( string, string ).
present_digits(string).

present_digits("") :- fail.
  present_digits( S ) :-
    frontchar( S, C, _ ),
    C>='0',C<='9',!.

present_digits( S ) :-
    frontchar( S, _, S2 ),
    present_digits(S2).
    
word_digits( "", "" ) :- !.

word_digits( S, O ) :-
    fronttoken( S, T, S2 ),
    present_digits(T),
    word_digits( S2, O2 ),
    concat( T, " ", O3 ),
    concat( O3, O2, O ), !.

word_digits( S, O ) :-
    fronttoken( S, _, S2 ),
    word_digits( S2, O ).


printThatShit:-
    write( "Enter string: " ),
    read(S),  nl,
    word_digits( S, Digits ),
    write(Digits).

Upvotes: 0

Views: 151

Answers (1)

TA_intern
TA_intern

Reputation: 2422

Your types are all over the place. In SWI-Prolog (which you are using) there are atoms, for example foo and 'Another atom', and moreover:

  • character codes (Unicode numerical value for the character) and a list of those:
?- atom_codes(foo, Codes).
Codes = [102, 111, 111].
  • chars (one-letter atoms) and a list of that
?- atom_chars(foo, Chars).
Chars = [f, o, o].
  • strings, which are a memory-efficient way of dealing with text
?- atom_string(foo, String).
String = "foo".

If you solved that part in your code you will be much further than now.

Another hint: read reads a Prolog term. If you want to just read some text, you need to read codes, chars, or an SWI-Prolog string. See read_line_to_codes or read_line_to_string or read_string etc. Once you decide on the data type you can decide on how to get the digits (or numbers?) out: DCG, regexp, just simple filter on a list?


Assuming you already have a working solution (you should actually post it as an answer!)

This is one way to do it using a DCG:

:- use_module(library(dcg/basics)).

line_digits([D|Ds]) --> digit(D), !,
    line_digits(Ds).
line_digits([]) --> "\n", !.
line_digits(Ds) --> [_],
    line_digits(Ds).

only_digits -->
    { format("Enter string: "), flush },
    line_digits(Ds),
    { format("~s~n", [Ds]) },
    !,
    only_digits.
only_digits --> eos.

To run it:

?- phrase_from_stream(only_digits, user_input).
Enter string: this is a string

Enter string: 234 this is another 3243 string999
2343243999
Enter string: ^D
true.

You stop it by typing Ctrl+D.

Quite a bit of code is needed to do the read-print loop. Maybe there is a cleaner way.

If you only had a list of say chars (one-character atoms) then this would be an easy way to do it:

only_digits(String, Digits) :-
    include(digit, String, Digits).

digit(C) :- char_type(C, digit).

To use it:

?- only_digits([a,b,c,'1','2','3',x,y], Ds).
Ds = ['1', '2', '3'].

Upvotes: 1

Related Questions