# Loading a string of data seperated by spaces and comma's

**URL:** <https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446>\
**Category:** Help!\
**Created:** [March 25, 2019, 2:44pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446 "2019-03-25T14:44:42Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![janjulius](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/janjulius/32/155_2.png) [@janjulius](https://swi-prolog.discourse.group/u/janjulius)\
**Post date:** [March 25, 2019, 2:44pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/1 "2019-03-25T14:44:43Z")

</div>

Hi.

I’m trying to load in data from the Runescape hiscores, the data structure is as follows:

Rank,Level,Xp(space)Rank,Level,Xp(space) etc.

Example data: [https://secure.runescape.com/m=hiscore\_oldschool/index\_lite.ws?player=swampletics](https://secure.runescape.com/m=hiscore_oldschool/index_lite.ws?player=swampletics)

559866,1305,16020717 448750,76,1336860 507980,73,993001 326590,90,5584463 471125,84,2983784 834444,71,830231 823142,49,94297 896577,65,466827 1103301,50,111220 629804,65,481761 733809,55,166760 655933,62,365270 421971,66,528570 673282,56,194564 736185,50,107826 448109,64,423037 654094,42,48234 456095,63,402594 257834,63,380955 572231,63,369397 704338,25,8146 -1,1,0 740105,19,4115 360108,53,138805 -1,-1 -1,-1 -1,-1 -1,-1 -1,-1 -1,-1 -1,-1 -1,-1 -1,-1

How can I load these into prolog so I can use them for equations, e.g see if entry 3 (players defence level) is higher than x?

I want to use assert to save the levels so they can be used when asking questions (for chatbot).

Thanks,  
Jan Julius

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [March 25, 2019, 3:45pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/3 "2019-03-25T15:45:25Z")

</div>

You could split the input on “white space”, then each element on comma. I will use `http/http_open` and strings for this.

(it seems the content is separated by newlines but this doesn’t matter too much. Just split on spaces, tabs, newlines.

```auto
$ cat runescape.pl 
:- use_module(library(http/http_open)).

load_highscores(URL, Highscores) :-
    setup_call_cleanup(
        http_open(URL, In, []),
        process(In, Highscores),
        close(In)).

process(In, Highscores) :-
    read_string(In, _, Str),
    split_string(Str, "\n\t ", "\n\t ", Lines),
    maplist(line_to_scores, Lines, Highscores).

line_to_scores(Line, Scores) :-
    split_string(Line, ",", "", Str_scores),
    maplist(number_string, Scores, Str_scores).

```

If you run this code you’ll see you now have a list of lists:

```nohighlight
?- load_highscores('https://secure.runescape.com/m=hiscore_oldschool/index_lite.ws?player=swampletics', Result).
Result = [[559896, 1305, 16020717], [448777, 76, 1336860], [507995, 73, 993001], [326604, 90, 5584463], [471151, 84, 2983784], [834489, 71, 830231], [823173, 49|...], [896481|...], [...|...]|...].

```

You can now go over the lines and assert them one by one, or just save the whole thing and get the lines by their number. It really depends though how you are going to use them.

---

<div class="post-metadata">

**Author:** ![janjulius](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/janjulius/32/155_2.png) [@janjulius](https://swi-prolog.discourse.group/u/janjulius)\
**Post date:** [March 25, 2019, 6:13pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/4 "2019-03-25T18:13:55Z")

</div>

Hi Boris,

I will check this out tomorrow and come back to you with the result thank you a lot for your time.

---

<div class="post-metadata">

**Author:** ![janjulius](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/janjulius/32/155_2.png) [@janjulius](https://swi-prolog.discourse.group/u/janjulius)\
**Post date:** [March 26, 2019, 4:26pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/5 "2019-03-26T16:26:38Z")

</div>

Hi Boris,

Your answer has helped me loads thanks for the contribution.

I have another question I will post it here, I could make a new topic too if you want but here it is (please do note I just do programming in C language usually):

Now with the data saved in list I can use it as so with this predicate:  
myskill(Skill, Level).

So for instance I can do

?- myskill(“Attack”, X).  
X = 50;

Now, There are quests taht require levels I defined them as such in my prolog:

requires\_skill(heroesquest, ‘53’, “Cooking”).  
requires\_skill(heroesquest, ‘53’, “Fishing”).  
requires\_skill(heroesquest, ‘25’ “Herblore”).  
requires\_skill(heroesquest, ‘50’, “Mining”).

Now I want to check if the player has the levels for a certain quest

So I came up with the following:

can\_do\_quest(Quest, Result) :-  
requires\_skill(Quest, Rl, Skill),  
atom\_number(Rl, ReqLevel),  
myskill(Skill, Level),  
Result is Level \> ReqLevel.

But it does not seem to work

thank you again.

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [March 26, 2019, 5:40pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/6 "2019-03-26T17:40:41Z")

</div>

> [@janjulius](#):
>
> But it does not seem to work

What does that mean? Do you get compilation errors? Warnings? Or it does something different from what you expect? What do you expect? How can I reproduce your problem?

---

<div class="post-metadata">

**Author:** ![janjulius](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/janjulius/32/155_2.png) [@janjulius](https://swi-prolog.discourse.group/u/janjulius)\
**Post date:** [March 26, 2019, 6:00pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/7 "2019-03-26T18:00:25Z")

</div>

Oh yeah, the error: ERROR: Undefined procedure: can\_do\_quest/2 (DWIM could not correct goal)

Also the goal is if the mystats returns a value lower than the skill it is checking it should return false and if no skill is lower than the required skill it should return true.

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [March 26, 2019, 6:29pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/8 "2019-03-26T18:29:38Z")

</div>

If you can share some code that I can copy-paste and you tell me what you did with it, then I can do as you did and see the problem. It becomes very easy to tell you what is wrong with it. If I have to reconstruct what you might have written and what you might have done and then tell you my opinion of how I feel about it, it becomes very difficult.

But the error you show means that something definitely went wrong, and `can_do_quest/2` is not defined at all. I see other problems as well, for example `Result is Level > ReqLevel` is almost certainly an error?

PS: use markdown for code. See [this post](https://swi-prolog.discourse.group/t/when-posting-using-mail-please-use-markdown/241).

---

<div class="post-metadata">

**Author:** ![janjulius](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/janjulius/32/155_2.png) [@janjulius](https://swi-prolog.discourse.group/u/janjulius)\
**Post date:** [March 26, 2019, 6:34pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/9 "2019-03-26T18:34:36Z")

</div>

Ah yeah I will in the future but to not clutter the post I have the code in a pastebin here:

[https://pastebin.com/YU0DqD3h](https://pastebin.com/YU0DqD3h)

Thank you for your time!

test data:

```auto
-? load_skills('lynx titan', Result), can_do_quest(heroesquest).

```

should return true

```auto
-? load_skills('swampletics', Result), can_do_quest(heroesquest).

```

should return false

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [March 26, 2019, 7:40pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/10 "2019-03-26T19:40:56Z")

</div>

Well, if I put your code in a file and try to compile it, I get two errors and a warning. I don’t think you can expect much before you figure out what the errors are.

---

<div class="post-metadata">

**Author:** ![janjulius](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/janjulius/32/155_2.png) [@janjulius](https://swi-prolog.discourse.group/u/janjulius)\
**Post date:** [March 26, 2019, 8:02pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/11 "2019-03-26T20:02:07Z")

</div>

How do you compile the code? I just load up the file using the command prompt.

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [March 26, 2019, 8:06pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/12 "2019-03-26T20:06:27Z")

</div>

You show me yours I’ll show you mine. How do you load your code using the command line? You can just copy-paste whatever it is you type in and the output, it can’t be that much?

---

<div class="post-metadata">

**Author:** ![janjulius](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/janjulius/32/155_2.png) [@janjulius](https://swi-prolog.discourse.group/u/janjulius)\
**Post date:** [March 26, 2019, 8:46pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/13 "2019-03-26T20:46:46Z")

</div>

Oh, I figured it out no problem I didnt realise using the executable compiles the code sorry that is my bad.

But I’ve fixed the errors:

[https://pastebin.com/8mBP9mXD](https://pastebin.com/8mBP9mXD)

As for what I’m trying to achieve.

I want to check all the levels for a quest in this case the heroesquest if any of the players levels is below the required ones it should return false if this is not the case it should return true I just have trouble figuring out how to do it.

My attempt at this:

```auto
can_do_quest(Quest, Result) :-
	requires_skill(Quest, Rl, Skill), 
	atom_number(Rl, ReqLevel),
	myskill(Skill, Level), 
	Level @>= ReqLevel.

requires_skill(heroesquest, '53', "Cooking").
requires_skill(heroesquest, '53', "Fishing").
requires_skill(heroesquest, '25', "Herblore").
requires_skill(heroesquest, '50', "Mining").

```

This works however it returns all the instances of the level comparisons e.g results:

A player missing one level expected false  
actual:

```auto
can_do_quest(heroesquest,X).
true ;
true ;
true.

```

a player missing no levels expected: true  
actual:

```auto
can_do_quest(heroesquest,X).
true ;
true ;
true ;
true.

```

thanks again.

Also I would like to add I’m probably thinking too much of methods than predicates.

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [March 26, 2019, 9:19pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/14 "2019-03-26T21:19:41Z")

</div>

I do the following: I take the complete source as you have put on pastebin, then save it to a file called `rs.pl`. Then, in the same directory as the file:

```auto
$ swipl -q
?- [rs].
Warning: .../rs.pl:42:
	Singleton variables: [X]
Warning: .../rs.pl:55:
	Singleton variables: [Result]
true.

```

Don’t ignore warnings. They are almost always errors in SWI-Prolog.

Either way, if you want to make sure that _all_ the requirements are fulfilled, you might need something like `foreach/2`. I am not sure, but something like:

```nohighlight
foreach(
    requires_skill(heroes_quest, Level, Skill),
    ( myskill(Skill, My_level), My_level >= Level) )

```

In a more procedural reading, what you have right now is about the same as:

```nohighlight
for skill in required_skills:
   if have skill then print "true"

```

and what you probably want is:

```nohighlight
if have skill A
        AND have skill B
        AND ...
        AND have skill Z
   then print "true"

```

You can use `foreach/2` to make this chain of ANDs for you. The “conjunction” the documentation talks about is exactly this `a AND b AND ...`

---

<div class="post-metadata">

**Author:** ![janjulius](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/janjulius/32/155_2.png) [@janjulius](https://swi-prolog.discourse.group/u/janjulius)\
**Post date:** [March 26, 2019, 9:48pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/15 "2019-03-26T21:48:06Z")

</div>

You are a hero, I got it.

This was what got me what I wanted:

```auto
can_do_quest(Quest) :-
	foreach(
     (requires_skill(Quest, Rq, Skill), atom_number(Rq, Level),myskill(Skill, My_level)),
		(My_level @>= Level) ).

```

Thank you so much for your help and time Boris I have managed to understand Prolog a lot more with your assitance.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 27, 2019, 8:52am UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/16 "2019-03-27T08:52:15Z")

</div>

Great. Two small remarks. First, `@>=` is for _standard order comparison_. Considering you converted to numbers, you probably want `>=`. Second, `foreach/2` requires some understanding. In most cases where you merely have a generator and independent checks you can use the much simpler `forall/2`. This is simple defined as `\+ (Generator, \+Test)`, i.e., there is no answer from _Generator_ for which _Test_ fails.

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [March 27, 2019, 8:59am UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/17 "2019-03-27T08:59:45Z")

</div>

Aah, I see. I admit I got trigger-happy because I have been trying to find a good excuse to use `foreach/2` for a long time. Now after your comments I realize that a) it doesn’t seem to be needed in this case and b) I still haven’t found a realistic use case for `foreach/2` and finally c) I don’t have the understanding that `foreach/2` requires.

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [March 27, 2019, 9:12am UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/18 "2019-03-27T09:12:06Z")

</div>

Now that I read the documentation yet again, I see:

> The implementation executes [forall/2](http://www.swi-prolog.org/pldoc/man?predicate=forall/2) if Goal does not contain any variables that are not shared with Generator.

And the code clearly says:

```plaintext
  562 foreach(Generator, Goal) :-
  563 term_variables(Generator, GenVars0), sort(GenVars0, GenVars),
  564 term_variables(Goal, GoalVars0), sort(GoalVars0, GoalVars),
  565 ord_subtract(GoalVars, GenVars, SharedGoalVars),
  566 ( SharedGoalVars == []
  567 -> \+ (Generator, \+Goal) % = forall(Generator, Goal)
  568 ; % and so on

```

So the `can_do_quest/1` definition above ends up in line 567, just as a query like:

```prolog
?- foreach(between(1, 3, X), between(1, 5, X)).

```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 27, 2019, 9:17am UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/19 "2019-03-27T09:17:10Z")

</div>

Foreach creates a _conjunction_ from the answers of the generator. That is, it does not call essentially `\+ \+ Test` but simply `Test`. This makes a difference if you want to maintain the bindings or choice points of _Test_. The first is notably useful for _constraints_. For example

```
foreach(some(P), dif(X, P))

```

This works fine, while if you use this with forall/2 it won’t. I think you can figure out why.

---

<div class="post-metadata">

**Author:** ![janjulius](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/janjulius/32/155_2.png) [@janjulius](https://swi-prolog.discourse.group/u/janjulius)\
**Post date:** [March 27, 2019, 12:36pm UTC](https://swi-prolog.discourse.group/t/loading-a-string-of-data-seperated-by-spaces-and-commas/446/20 "2019-03-27T12:36:09Z")

</div>

Thanks to both of you for your input, you guys have been of immense help.
