4 kyu
Simplexer
250 of 750Mihail-K
Loading description...
Strings
Parsing
Algorithms
View
This comment has been reported as {{ abuseKindText }}.
Show
This comment has been hidden. You can view it now .
This comment can not be viewed.
- |
- Reply
- Edit
- View Solution
- Expand 1 Reply Expand {{ comments?.length }} replies
- Collapse
- Spoiler
- Remove
- Remove comment & replies
- Report
{{ fetchSolutionsError }}
-
-
Your rendered github-flavored markdown will appear here.
-
Label this discussion...
-
No Label
Keep the comment unlabeled if none of the below applies.
-
Issue
Use the issue label when reporting problems with the kata.
Be sure to explain the problem clearly and include the steps to reproduce. -
Suggestion
Use the suggestion label if you have feedback on how this kata can be improved.
-
Question
Use the question label if you have questions and/or need help solving the kata.
Don't forget to mention the language you're using, and mark as having spoiler if you include your solution.
-
No Label
- Cancel
Commenting is not allowed on this discussion
You cannot view this solution
There is no solution to show
Please sign in or sign up to leave a comment.
(C#) The description makes no mention of handling null values, yet "Test Empty" in the hidden test cases tests with a null value. It's also unclear what "Text Exception" is testing, or what it's passing. It seems to expect false when my otherwise-valid solution returns true. The only valid case in C# for an IEnumerator to throw an exception is if the underlying collection is modified during iteration. Strings are immutable so this is an unreachable scenario.
This comment has been hidden.
I enjoyed this kata since I'm a big fan of regular expressions, But it's more suited at 5kyu instead of 4.
There is a strange requirement: "true123 is an identifier, as opposed to boolean followed by integer".. Looks like foreign for this task. Actually I ignored it (did not check and maintain this case). And my solvation passed all tests! May be you should remove this requirement from kata description?
Which language did you solve in?
Java
To pass "testException" in Java you have to throw an exception in "next()" if the string is empty, which is not obvious. Returning null or new Token(null, null) in "next()" or false in "hasNext()" doesn't work.
I don't know Java, but a quick search reveals that
next()
should throw an exception when there's nothing more to return. Since this is the official spec of the interface, I'd say it's rather more obvious than not.Oh, you are right.
Thanks, I was struggling on this one :)
Rust translation ready for review.
approved
Failed with just one test
But don't know what "ReferenceError: cons is not defined" could mean under the hood, because in local
Set the log on input and output and output as expected for test: My output: Token { text: 'true', type: 'boolean' }
Expected by the test:
You seem to have outdated sample tests. You can either:
I think this kata is valuable as a precursor to all those other parsing-related kata, which require a lexer as a fundamental part of the solution. However, it is currently in a deplorable state.
Therefore, I've authored a Fork (in Python) that completely reworks everything. In particular:
string
tokens should match any character between quotes, including whitespaceThe point about
string
s in particular happens to be a breaking change for most of the current regex-based solutions in Python, although strictly speaking it's the fault of users for not writing proper regexes. Granted, the current tests don't actually enforce anything, but still...I would invite users to review the fork, add suggestions in the forks's discourse, and if consensus is achieved that it merits approval, work on adding language specific blocks where appropriate for existing languages. That means that the current fork is not meant for approval in its current state (since it lacks all language specific stuff apart from Python), rather as a template to be worked off of.
I have gathered input and tuned the details of my fork, then went ahead and approved it.
Missing random tests in Java.
Also (probably) needs improved fixed tests to match new spec.
Missing random tests in C#.
Also (probably) needs new fixed tests to match new spec.
JavaScript should use chai for assertions. Fixed here
Approved
JavaScript: Insufficient test cases and no random tests. Most solutions (including the sample solution) are incorrect.
Fixed here.
Approved
this note in the description is now obsolete:
JavaScript fork(s):
Approved
could you update the initial code to use a
class
as well ?done
thanks for your efforts ! had to refactor my solution a bit so that it passes the tests again ... ;-)
Javascript:
assertSimilar is deprecated, use assertDeepEquals
Fixed by latest fork
Java question: I'm a little confused on what to do with an empty string or null... I'm throwing a NoSuchElementException() in the case that it isn't a valid string but it is saying that I'm still failing the test.
Figured it out. For others who may run into this issue in Java, I was throwing the noSuchElement exception which was interrupting before the expected "return false". Don't throw the exception like it says in the description, just have the hasNext() method return false.
I understand almost nothing from the description of this Kata and the examples given just can't make up for the 75% missing explanation. Can someone please explain me what I even have to do for this Kata?
You are given a string that you have to parse into tokens, which you can see in the "Token Grammar". For example: str = 'return "String" + "number"' From the table you must map each part of the string to a token from the table result_tokens = 'return' - keyword; ' ' - whitespace; 'String' - string; ' - whitespace; 'number' - string In addition, you need to implement an iteration protocol. I hope this makes more sense to you.
This is not true for Python. IMO, this requirement should be removed from other languages if it's actually present there.
No random tests.
Opened as separate issues per language.
Is there something wrong with the error message? I'm literally returning exactly what I'm supposed to...
[Token(chars='x', type='identifier')] should equal [Token(chars='x', type='identifier')]
[Token(chars='true', type='boolean')] should equal [Token(chars='true', type='boolean')]
[Token(chars='12345', type='integer')] should equal [Token(chars='12345', type='integer')]
[Token(chars='"String"', type='string')] should equal [Token(chars='"String"', type='string')]
[Token(chars='break', type='keyword')] should equal [Token(chars='break', type='keyword')]
Can someone review my translation in Rust ?
Would someone review if I make a translation in Rust ?
I think so. There's a couple of active Rust users, so someone should be able to take a look.
Very interesting Kata, thank you.
Did anyone produce any special solution for the keywords not being captured among identifiers? Was it just the word order?
This is what I get when I run the skeletal code: expected:<[Token{text=return, type=keyword}, Token{text= , type=whitespace}, Token{text=x, type=identifier}, Token{text= , type=whitespace}, Token{text=+, type=operator}, Token{text= , type=whitespace}, Token{text=1, type=integer}]> but was:<[]>
Shouldn't the actual portion be <[ Token{text=x, type=identifier}]> ?
why should it? Did you print the input string?
I actually don't even find this expected result in the test suite, so I've no idea what you did.
EDIT: if you have several return statements, I'd bet you returning from the one you don't expect, there.
The expected result is from testStatement. The actual result was from running the skeletal program provided: i.e. I didn't add ANY code to what was given. The only return statement is in the next() method: return new Token("x", "identifier");
Thank you for responding to me.
there are 2 tests in that method. The first one is:
"return x - 2"
, which expectes something like you said, except with a2
in the end, and not a1
. I still don't get why it should return locally but not on cw, but here is a general advise: don't trust what you do locally (except if you have everything in the sample tests part. Here, there are stuff in the preloaded section you don't have access to so... hard to tell).Shortest way might be that you post your code with a spoiler flag, I guess...
This comment has been hidden.
plz use correct markdowns formatting (otherwise it's a bit of a pain to read the code. Hopefully, it's not critical in java...)
I cannot run the sample tests with your code, actually (even after adding the imports). But for what I can see in the constructor, it seems you're consuming the iterator right into it (because of the last while loop), meaning you're not actually implementing an iterator (that should be consumed "from outside"). Hence, if you tried your code locally, I guess you didn't reproduce the sample tests correctly.
Thank you. It will take me some time to fully understand what you've written. In the meanwhile, what is 'cw'?
Also, I'm doing this in Java, maybe that's why our tests are different? (testStatement uses "return x + 1" for me.)
cw==codewars
;)Nope, I looked at the Java version too. so it's definitely... wait... Ah ok... you're looking at the sample tests while I was looking at the test cases part... :/ For some reason the 1 became a 2 in the former...
about what I said: at the very end of the contructor, if you
System.out.println(hasNext())
, you'll see it returns false, hence your iterator is already consumed, and that's the reason you get an empty array in the tests.I understand!! My code works for all sample tests and test cases EXCEPT for the testEmpty test case. This is weird because the sample tests have a testEmpty also, and I passed that one. In both tests, the buffer parameter was "" and its length 0. The test case just says it failed so I have no idea what to correct. Are you able to give me a clue or is that cheating?
could you post your complete/working current code, plz? (with imports and all: last time it didn't work on cw)
This comment has been hidden.
:+1:
ok, it's actually pretty simple: in the test cases part, that method contains another test. It's a classic stuff/problem, in java... x)
You should just... either read the error message or print the actual input to the console. Then you'll pretty quickly be done with it.
Note: printing stuff to the console should be your number one reflex ;p
I finally re-read the instructions and worked out how to handle null :) Thank you for all your help.
The error output string should be changed. I was recieving a lot of these types of errors when submitting tokens with integer (rather than the expected string) values:
This made it much more difficult to debug than it needed to be for what I think are obvious reasons.
Cheers
having to handle the
null
case seems out-of-scope for this kind of problem. it's more of a tacked-on "gotcha" for those who skim through the spec than any sort of real programming challenge. i would suggest omitting it(fwiw, a language with nullable/non-null types (e.g. kotlin) would likely write this function's signature such that it accepts a non-null
String
, because it just doesn't make sense to ever be passing null to this function -- the lack of a value should be handled by the caller because it's not within the scope of a function whose sole purpose should be string processing)I highly suggest to rewrite the description. I have read it like 3 times and still no clue what the code should do.
Example input and example output would be help a lot.
It took me around an hour to understand what is going on. Seriously, update of this description is required because of two main reasons:
My code can pass the testSingle case in RUN SIMPLES TESTS but why it fails through the ATTEMPT
see here
I get the js heap out of memory error when i run the base code that was already prepared
C# translation added!
I think there's a mistake in the C# version. In line three there's the class Simplexer : Iterator but I think it should be class Simplexer : IEnumerable. Am I correct?
has been approved
This comment has been hidden.
Python: Could you add
tester("forecast", [Token("forecast", "identifier")])
to the tests? Some solutions yieldToken(chars='for', type='keyword')
,Token(chars='ecast', type='identifier')
.At least in the Python version, the way the test is written forces us to use Simplexer as both an iterable and an iterator. Even though it's uncommon to parse a program more than once, it is considered poor practice to have the iterable and iterator be the same object, because it prevents using multiple iterators in parallel, in nested loops over the same iterable, for example. If you want to permit solutions that separate the iterable (a Simplexer class, containing an _iter_ method and returning an iterator) from the iterator, (perhaps called something like a SimplexIterator, containing a _next_ method), the tests need to say something like
iterator=iter(Simplexer(test_str))
and then usenext(iterator)
everywhere you might have used next on the Simplexer object itself instead.Hi bouchert,
Sorry, I forgot your message. You'll have to assist me a little, on this one. ;o
So, if I follow you correctly, the part that cause problem in the tests is (note: I removed the try/axpect part because it has nothing to do with our problem: retrocompatibility with the first translation):
That's it?
If I look at the original version (Java), the implementation asked for is explicitly an iterator. Ok, so that would be a stuff WITH the
__next__
method in python. But I read (stackoverflow, if I remember well. For what it (may) worth(s) (??) ) that in python, an object implementing__next__
has to implement__iter__
all together. It's a bit annoying because on one hand, the descirption ask for in iterator, but on the other hand, if I understood you well, to ask for an iterator "the right way" in python would lead to ask for 2 objects to the warriors, right? Or do you suggest that I use this iterator on my side, and ask to the warrior only for the iter method? (but this way, I have a feeling of being far from the description).What's your opinion about that? (did I understood correctly??)
Cheers,
B4B
Yeah, you've found, the trouble spot. But first I want to emphasize that no, an object implementing
__next__
does not have to implement__iter__
, and in fact shouldn't unless you're really sure that's what you want and your users know you can only have one valid iterator per Simplexer at a time.I feel a bit bad for nitpicking about this, because in this particular situation, it really doesn't matter that much. But it does muddy the usefulness of separated iterator/iterable roles, so I wanted to at least point it out. Before I explain further, here's a simple way of fixing the tests: Basically, your tests can be compatible with both ways as long as you wrap any calls to Simplexer's constructor with
iter()
before then callingnext()
manually on it. Normally, it's called implicitly byfor
...in
, but because you're manually callingnext
, you'll need to also manually calliter
. So instead ofsimplex = Simplexer(test_str)
justsimplex = iter(Simplexer(test_str))
. This simple change only works if you never want to reset the iterator to the beginning of the input string. Otherwise, you should save the Simplexer object and useiter
on it each time you want to generate a fresh iterator. (And hold onto each iterator, of course, until either it is exhausted or you're done callingnext
on it.)You can read more about the distinction between iterables and iterators at https://stackoverflow.com/questions/9884132/what-exactly-are-pythons-iterator-iterable-and-iteration-protocols Implementing next and iter in the same object is only really right if you have a stream that can't ever be rewound, and even then, you want to make sure people know about that restriction.
Basically, unless
iter
returns a unique object every time it's called, there's nowhere but the Simplexer itself to store state information about how far along in lexing we've gotten. If we for some reason decide to run two nested iterators, for example, they will step on each other, stealing each other's next values, because they're using the same "cursor" as they advance through the input. If, however, we separate theSimplexer
and theSimplexIterator
, then we can have theSimplexer
's__iter__
method return as many freshSimplexIterator
s as we like, each maintaining an independent pointer into the input data, which we advance using its__next__
method.For further insight, note that this is how Python does other built-in iterables.
list
doesn't implement__next__
for example. But its__iter__
method will return an internallist_iterator
(same astype(iter([]))
) which does implement__next__
and keep track of its place in the list.I hope this was clear enough. Let me know.
This comment has been hidden.
Python
Actual and expected results are swapped in random test cases.
thx, should be good, now.
RegEx fun
JavaScript version should not test for
null
, but forundefined
, behaving as an empty string.Usually
null
is used for such purposes instead ofundefined
. SeeRegex.prototype.match
.Besides, I don't think that's too much of a big deal. :)
Default arguments don't work for
null
as they do forundefined
.The use case of
Regex.prototype.match
is different (there,null
is an output, not an input), and that output should have been[]
instead ofnull
anyway.Default arguments should pattern-matches missing arguments. It's just that for some reason in JS default argument also pattern-matches
undefined
(I have a kata about that).And that's not how default arguments are supposed to work: If you're writing C#/Java/Python/whatever you pattern-matches the exact number of arguments passed into the function. Passing
null
inside a function explicit also counts as passing an argument into the function.null
represents "not a thing", whileundefined
represents "no arguments". They're semantically different in meaning.So I don't think
undefined
should be used in this case, because the spec mentions "empty string", not "no arguments".I think
undefined
should be used for exactly the reasons you're pointing out. This is JavaScript, not any other language, so default arguments work as specified in JavaScript (ECMAscript, some variant of, ..).And empty string is
""
, notnull
. Empty argument comes through asundefined
, and good luck differentiating betweenundefined
andmissing
.I don't think we're going to agree on this. We both understand reasonably well what is happening, but we are reaching different conclusions from that.
You can simply edit the kata and modify the js tests
It's not my kata and there does not seem to be consensus.
Two different people have closed this issue because they don't see the problem, and Blind, who has adopted the kata, must be watching with a pot of popcorn seeing if anybody is going to convince anybody.
I had actually decided to just shut up about the subject with other people's kata and just vote my satisfaction.
Test removed from the JS version (it's not so important) and description updated.
Reading the tests, I noticed
toList(lexer)
. Given all the effort to have lexer behave as an iterator, wouldArray.from(lexer)
work? Or am I confused with generators now?Sorry, didn't see your message before.
...but I'm fully incompetent to answer your question... ;-/ (you can try it on your side in a fork, if you want to be sure)
Oh, it won't work. I was confused with "iterable". ( I :heart: MDN. )
( And I miss messages all the time too. Notifications aren't perfectly reliable, and I'm not either. :P )
("mdn" ? ;o )
Mozilla Developer Network (or mdn.io).
Interesting.
(JavaScript)
null
is not aString
. If you want to pass in an empty string, that would be""
.ok?
Ehm, no, not really. Please explain to me why I have to handle
null
.null
is not aString
(it's anObject
). CallSimplexer()
and you getundefined
, notnull
(and I can handleundefined
much more natural thannull
).The only reason someone ever brought up that made some (but still not enough) sense was that if your input is the result of something that failed, you might get a null pointer dereference. But in that case, you get an
Error
(exception), not anull
string. It'd be a dereference, not a cast.Anyway I look at it, a
null
String
is""
, notnull
. An invalid string leads toError
, notnull
. I should not have to handlenull
if my input is aString
.Unless you take the easy out and say "because I say so" (you could. your kata, your rules). Then my question would be why I don't have to handle
new RegExp(false)
as an input string. Because that's equally unapplicable.I just don't get it. Please enlighten me.
Er... I don't do JS at all (and I'm not the original author either, so I deal with what was the original task too! ;) )
In Java, handling the null input is a classic task, even if the input type is supposed to be something else. So in Java, that makes sens. In the 3 languages, null/None and the empty string cases are implemented in the tests. I can't talk about JS, but in Java, there are sure cases where your function recieve
null
instead of whatever the input should be without recieving an error instead ofnull
.Actually I don't think that you should have this conversation with me because I have absolutely no background to argument anything, but Myjinxin approved the kata and is competent in JS, so you should see that with him, to decide if this special test has to be removed in JS or not.
Could you explain how it makes sense in Java?
Er... I thought I just did :o (might be my sentences weren't clear enough ? (A bit tired this evening and not my mother tongue)
You say it's a classic task, but that doesn't explain why.
And you say there are cases where your function receives
null
, but you don't tell me what such a case might be. It might not be applicable to JavaScript.So I was trying to get some more clarification. Not a whole lot, just a little. If I still don't understand, I'll ask again.
Could you explain a little more?
Well, I can try ;) (but no guranties that I succeed!)
First, I think that Java and JS are effectively quite different on this point (in Java, null isn't an object).
So, with that, the null value could be sent from one method, carried through several others if no checks are done, and finally create unexpected bugs/behaviour far away from the point where it was generated. For that reason, it's considered bad practice to use null values in a java implementations (that can lead to create specific objects to be used as default values: numerous lines of code, just to use something else than null. For example, following these recommandations with linked lists, one should use a specific "EmptyNode()" object for the empty list instead of just the null value. The list being represented by
Node->Node->EmptyNode
instead ofNode->Node->null
).But some people use null anyway (well, that's way shorter to code! ;o ). So if you want to create a robust code that could by reused anywhere, in any context and if you want to avoid the maximum of complaints from clients (saying that your code bugs even if this is a null value coming from their side that cause the bug), you have to be sure that your code doesn't allow the null value to be passed through your code. And that's the reason why, in Java, it's perfectly current (and even good practice) to handle the null value as input for any kind of input.
I hope this is understandable and that I didn't say too much bullshit (keep in mind that I do java for less than a year, that I'm not professionnal coder and that java isn't my first coding language. The first being python which has almost nothing in commun with the former... :-/ ).
Cheers (...and bed time for me, now! ;) (Ooo, damn, the night will be short :-/ ) )
In Java I got also nulls as input but I don't think it's a problem.
It just take you 10 seconds to add an
if
statement to solve this.Blind, thank you so much for that explanation.
Java's
null
maps to JavaScript'sundefined
: declared but not (possibly yet) defined. And it is what you get when you callSimplexer()
i.e. without any arguments.That means that the
null
test in JavaScript is fundamentally different from thenull
test in Java, and should be anundefined
test. Which is solvable quite naturally.Ice, I'm going to reopen this issue. Even if you don't think something is a problem because you can take a blunt axe to a Gordian knot, you might have the decency to give someone else the opportunity to unravel it. Which Blind just did for me. But I would like this issue resolved, and not just closed.
I think you're wrong about this.
https://stackoverflow.com/a/18808270/3664611
You're correct, it's a primitive.
Which is Not A String.
ok...
Have fun, guys!
!!! DISCLAIMER !!!
Kata is approvable. Awaiting a JS competent moderator who could be nice enough to implement the exception test in JS before to approve it!
Thx!!
!!! DISCLAIMER !!!
EDIT: remainder: the original author isn't anymore on cw...
Sorry. I only read the first sentence:
Kata is approvable
. Then I approved it. But I have no time to write test for it. Sorry :]Damn! ;) ok, no worry. I'll just downrank it to 5kyu (because it doesn't worth more, I believe. Don't you think? )
thanks anyway! :)
I'll write some random tests for it. maybe tomorrow, or tomorrow's tomorrow..(If I have time, Hmm.. and computer ;-)
.
message deleted (again and again cw error)
A little issue in Python, could you have a look?
Blind4Basics, since the author's gone, would you please look at my question re why I'm getting [] as my actual. Thank you so much.
Fun Kata. Thanks :-)
Could you give the bigenner the hint about the 'Iterators'?
not an issue.
(Python)
When I try to create a
Token
object as follows:Token()
, I get the following error:TypeError: init() takes exactly 3 arguments (1 given)
. I suppose I should pass text and type as constructor parameters, but this is never described in the kata description.solved
(Python)
My method raises
AttributeError
in that case, that fails the test. It should be specified, what kind of exception is expected.solved in python and java.
(Python) Why Simplexer has to be callable? Why calling
Simplexer.simplex("x")()
instead of justSimplexer.simplex("x")
?solved
"If no tokens are available, the next method should throw an exception": Maybe you could specify what kind of Exception you want thrown? (IllegalArgumentException ?)
Also due to a bug in CW the empty test passes even if you don't check for null input due to a NullPointerException. https://github.com/Codewars/codewars.com/issues/21
This comment has been hidden.
alright, thank you! Accepted.
What is the lexer supposed to do with unrecognized tokens? What is the expected result for the input "0 ~ 1"?
The expected solution is a naive one. Basically, assume all input will be valid.
agh! Finally finished this - my answer works, though verbose. My only observation is that failng tests require should state as a minimum what the expected value is.
Fantastic learning exercise though.
Am getting
testSingle(SimplexerTest) expected: but was:
Any help here? I have no idea what condition I am failing. All cases of a single 'token' have been covered?
Make sure that your solution handles whitespace tokens correctly. That's the best I can suggest with the given information.
This comment has been hidden.
I got the following error when I submitted my solution:
Why did that happen?
I was unable to reproduce the issue, and submitted a solution successfully. It might've been a one-off bug. Could you try refreshing the page and sumbitting again?
Your description says "If no tokens are available, the next method should throw an exception", but there are no tests for it. You should add one.
I liked this kata, though it took some superfluous reading to figure out what you actually wanted me to do. Ideally, you should give all necessary instructions in the description, rather than leaving the coder to look at the stub and example fixture to figure out how to do things.
Another couple of small issues would be nice to fix, also:
Because of how Test.assertEquals renders strings, it is very hard to see the whitespace problems. Perhaps you could write a custom function for it, to make it clearer on what to debug? I tend to wrap things in
<pre style='display:inline'> tags
.And a very minor typo:
There a 7 token types
should beThere are 7 token types
.