3

Is it possible in prolog to replace all white spaces of a string with some given character? Example- If I have a variable How are you today? and I want How_are_you_today?

false
  • 10,264
  • 13
  • 101
  • 209

3 Answers3

3

For atoms

There are may ways in which this can be done. I find the following particularly simple, using atomic_list_concat/3:

?- atomic_list_concat(Words, ' ', 'How are you today?'), atomic_list_concat(Words, '_', Result).
Words = ['How', are, you, 'today?'],
Result = 'How_are_you_today?'.

For SWI strings

The above can also be done with SWI strings. Unfortunately, there is no string_list_concat/3 which would have made the conversion trivial. split_string/4 is very versatile, but it only does half of the job:

?- split_string("How are you today?", " ", "", Words).
Words = ["How", "are", "you", "today?"].

We can either define string_list_concat/3 ourselves (a first attempt at defining this is shown below) or we need a slightly different approach, e.g. repeated string_concat/3.

string_list_concat(Strings, Separator, String):-
  var(String), !,
  maplist(atom_string, [Separator0|Atoms], [Separator|Strings]),
  atomic_list_concat(Atoms, Separator0, Atom),
  atom_string(Atom, String).
string_list_concat(Strings, Separator, String):-
  maplist(atom_string, [Separator0,Atom], [Separator,String]),
  atomic_list_concat(Atoms, Separator0, Atom),
  maplist(atom_string, Atoms, Strings).

And then:

?- string_list_concat(Words, " ", "How are you today?"), string_list_concat(Words, "_", Result).
Words = ["How", "are", "you", "today?"],
Result = "How_are_you_today?".
Wouter Beek
  • 3,307
  • 16
  • 29
  • Ok so basically it is converting string into lists and then back to string..Thanks a lot it worked. –  Nov 17 '14 at 13:44
  • 1
    @Peter Yet, notice that when you use the word "string" you actually mean "atom". SWI-Prolog also supports strings, but this is non-standard. I'll add a similar solution for splitting SWI strings to my answer. – Wouter Beek Nov 17 '14 at 13:46
  • @false Can't say that was entirely intentional ;-), but it may be just fine for this particular case. – Wouter Beek Nov 17 '14 at 13:55
  • 1
    Your nonvar-test make things worse, because it now fails for the most general query. I'd rather test for **one** `var/1` and then rely on the built-ins to do the rest. – false Nov 17 '14 at 14:42
  • @false Thanks, I've improved my definition a bit. It's still not quite there, e.g. `string_list_concat([], "/", "")` fails. However, I have never liked the fact that both `atomic_list_concat([], '/', '')` and `atomic_list_concat([''], '/', '')` succeed... – Wouter Beek Nov 17 '14 at 15:29
3

It all depends on what you mean by a string. SWI has several for them, some are generally available in any common Prolog and conforming to the ISO standard ; and some are specific to SWI and not conforming. So, let's start with those that are generally available:

###Strings as list of character codes — integers representing code points

This representation is often the default, prior to SWI 7 it was the default in SWI, too. The biggest downside is that a list of arbitrary integers can now be confused with text.

:- set_prolog_flag(double_quotes, codes).

codes_replaced(Xs, Ys) :-
   maplist(space_repl, Xs, Ys).

space_repl(0' ,0'_).
space_repl(C, C) :- dif(C,0' ).

?- codes_replaced("Spaces  !", R).
   R = [83,112,97,99,101,115,95,95,33]
;  false.

###Strings as list of characters — atoms of length 1

This representation is a bit cleaner since it does not confuse integers with characters, see this reply how to get more compact answers.

:- set_prolog_flag(double_quotes, chars).

chars_replaced(Xs, Ys) :-
   maplist(space_replc, Xs, Ys).

space_replc(' ','_').
space_replc(C, C) :- dif(C,' ').

?- chars_replaced("Spaces  !", R).
   R = ['S',p,a,c,e,s,'_','_',!]
;  false.

###Strings as atoms

@WouterBeek already showed you how this can be done with an SWI-specific built-in. I will reuse above:

atom_replaced(A, R) :-
   atom_chars(A, Chs),
   chars_replaced(Chs, Rs),
   atom_chars(R, Rs).

?- atom_replaced('Spaces  !',R).
   R = 'Spaces__!'
;  false.

So far everything applies to

###Strings as an SWI-specific, non-conforming data type

This version does not work in any other system. I mention it for completeness.

false
  • 10,264
  • 13
  • 101
  • 209
2

SWI-Prolog DCGs allows an easy definition, using 'push back' or lookahead argument:

?- phrase(rep_string(` `, `_`), `How are you`, R),atom_codes(A,R).
R = [72, 111, 119, 95, 97, 114, 101, 95, 121|...],
A = 'How_are_you'

The definition is

rep_string(Sought, Replace), Replace --> Sought, rep_string(Sought, Replace).
rep_string(Sought, Replace), [C] --> [C], rep_string(Sought, Replace).
rep_string(_, _) --> [].

edit To avoid multiple 'solutions', a possibility is

rep_string(Sought, Replace), Replace --> Sought, !, rep_string(Sought, Replace).
rep_string(Sought, Replace), [C] --> [C], !, rep_string(Sought, Replace).
rep_string(_, _) --> [].
CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • Try to type `;` or `SPACE` so see what happens: You get more than one answer. BTW: backquoted strings meaning codes is SWI-specific. – false Nov 17 '14 at 16:24