From: gotty Date: Mon, 27 Jan 2020 02:49:26 +0000 (+0300) Subject: [LIB-9] Add reserved, NAG and semicolon comment PGN tokens X-Git-Url: https://git.hedgecode.org/?a=commitdiff_plain;h=refs%2Fheads%2Fformat;p=chesshog.git [LIB-9] Add reserved, NAG and semicolon comment PGN tokens --- diff --git a/chesshog-format/src/main/java/org/hedgecode/chess/pgn/PGNUtils.java b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/PGNUtils.java index 884a388..ae5c046 100644 --- a/chesshog-format/src/main/java/org/hedgecode/chess/pgn/PGNUtils.java +++ b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/PGNUtils.java @@ -32,6 +32,7 @@ public final class PGNUtils { private static final String SHIELD_REGEX = "\\\\"; private static final String EMPTY = ""; + private static final String TAB = "\t"; private static final String CRLF_REGEX = "\\r?\\n"; public static String match(String source, String regex) { @@ -82,6 +83,10 @@ public final class PGNUtils { return pgn.replaceAll(CRLF_REGEX, PGN_SPACE); } + public static String tabCrlf(String pgn) { + return pgn.replaceAll(TAB, PGN_SPACE).replaceAll(CRLF_REGEX, TAB); + } + private PGNUtils() { throw new AssertionError( String.format("No %s instances!", getClass().getName()) diff --git a/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/CommentToken.java b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/CommentToken.java index 59feecb..22e5a0a 100644 --- a/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/CommentToken.java +++ b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/CommentToken.java @@ -29,13 +29,37 @@ import org.hedgecode.chess.pgn.entity.Moves; */ public class CommentToken implements Token { - private static final String COMMENT_REGEX = "^\\s*\\{([^}]+)\\}"; - private static final Pattern COMMENT_PATTERN = Pattern.compile(COMMENT_REGEX); + enum Type { + + BRACE ( BRACE_PATTERN ), + SEMICOLON ( SEMICOLON_PATTERN ); + + private Pattern pattern; + + Type(Pattern pattern) { + this.pattern = pattern; + } + + public Pattern pattern() { + return pattern; + } + } + + private static final String BRACE_REGEX = "^\\s*\\{([^}]+)\\}"; + private static final Pattern BRACE_PATTERN = Pattern.compile(BRACE_REGEX); + private static final String SEMICOLON_REGEX = "^\\s*;([^\t]+)\t"; + private static final Pattern SEMICOLON_PATTERN = Pattern.compile(SEMICOLON_REGEX); private static final int COMMENT_GROUP = 1; + private Type commentType; + + public CommentToken(Type type) { + this.commentType = type; + } + @Override public int token(Moves moves, String pgn) throws ParseException { - Matcher matcher = COMMENT_PATTERN.matcher(pgn); + Matcher matcher = commentType.pattern().matcher(pgn); if (!matcher.find()) { throw new ParseException("parse.pgn.incorrect.comment", pgn); } else { diff --git a/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/MoveToken.java b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/MoveToken.java index ea89dfc..0191ad4 100644 --- a/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/MoveToken.java +++ b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/MoveToken.java @@ -23,7 +23,6 @@ import org.hedgecode.chess.ParseException; import org.hedgecode.chess.pgn.entity.DetailMove; import org.hedgecode.chess.pgn.entity.MoveNumber; import org.hedgecode.chess.pgn.entity.Moves; -import org.hedgecode.chess.pgn.nag.Glyph; import org.hedgecode.chess.pgn.token.san.CommonSANToken; import org.hedgecode.chess.pgn.token.san.SANToken; @@ -34,7 +33,7 @@ import org.hedgecode.chess.pgn.token.san.SANToken; */ public class MoveToken implements Token { - public static final String MOVE_REGEX = "^\\s*([PNBRQKa-hx1-8=+#\\-O!?]+)(\\s+\\$([0-9]+))?"; + public static final String MOVE_REGEX = "^\\s*([PNBRQKa-hx1-8=+#\\-O!?]+)"; private static final Pattern MOVE_PATTERN = Pattern.compile(MOVE_REGEX); private static final int MOVE_GROUP = 1, NAG_GROUP = 3; @@ -46,9 +45,9 @@ public class MoveToken implements Token { MoveNumber moveNumber = new MoveNumber( moves.currentMove().ply() ); - int numberLength = moveNumberToken.token(moveNumber, pgn); - if (numberLength > 0) { - pgn = pgn.substring(numberLength); + int numLength = moveNumberToken.token(moveNumber, pgn); + if (numLength > 0) { + pgn = pgn.substring(numLength); } Matcher matcher = MOVE_PATTERN.matcher(pgn); if (!matcher.find()) { @@ -62,16 +61,8 @@ public class MoveToken implements Token { moves.addMove( detailMove ); - String glyph = matcher.group(NAG_GROUP); // todo: more then one NAG - if (glyph != null) { - detailMove.addGlyph( - Glyph.byNumber( - Integer.parseInt(glyph) - ) - ); - } } - return numberLength + matcher.group().length(); + return numLength + matcher.group().length(); } } diff --git a/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/MovesToken.java b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/MovesToken.java index 78de96c..fd0f21c 100644 --- a/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/MovesToken.java +++ b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/MovesToken.java @@ -32,10 +32,13 @@ public class MovesToken implements Token { enum Type { - MOVE ( new MoveToken() ), - COMMENT ( new CommentToken() ), - VARIATION ( new VariationToken() ), - RESULT ( new ResultToken() ); + MOVE ( new MoveToken() ), + NAG ( new NAGToken() ), + BRACE ( new CommentToken(CommentToken.Type.BRACE) ), + SEMICOLON ( new CommentToken(CommentToken.Type.SEMICOLON) ), + VARIATION ( new VariationToken() ), + RESULT ( new ResultToken() ), + RESERVED ( new ReservedToken() ); private Token token; @@ -50,17 +53,21 @@ public class MovesToken implements Token { private static final String MOVES_REGEX = "^\\s*([^\\s])"; private static final Pattern MOVES_PATTERN = Pattern.compile(MOVES_REGEX); + private static final int TYPE_GROUP = 1; private static final String RESULT_REGEX = "^\\s*(1-0|0-1|1/2-1/2|\\*)"; private static final Pattern RESULT_PATTERN = Pattern.compile(RESULT_REGEX); - private static final String COMMENT = "{"; + private static final String NAG = "$"; + private static final String BRACE = "{"; + private static final String SEMICOLON = ";"; private static final String VARIATION = "("; + private static final String RESERVED = "<"; @Override public int token(Entity entity, String pgn) throws ParseException { int pgnLength = pgn.length(); - pgn = PGNUtils.stripCrlf(pgn); // todo: starting with ";" comments + pgn = PGNUtils.tabCrlf(pgn); boolean isResulted = false; Type tokenType = tokenType(pgn); while (tokenType != null) { @@ -82,13 +89,22 @@ public class MovesToken implements Token { } else { Matcher moveMatcher = MOVES_PATTERN.matcher(pgn); if (moveMatcher.find()) { - switch (moveMatcher.group(1)) { - case COMMENT: - type = Type.COMMENT; + switch (moveMatcher.group(TYPE_GROUP)) { + case NAG: + type = Type.NAG; + break; + case BRACE: + type = Type.BRACE; + break; + case SEMICOLON: + type = Type.SEMICOLON; break; case VARIATION: type = Type.VARIATION; break; + case RESERVED: + type = Type.RESERVED; + break; default: type = Type.MOVE; } diff --git a/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/NAGToken.java b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/NAGToken.java new file mode 100644 index 0000000..e598e01 --- /dev/null +++ b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/NAGToken.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018-2020. Developed by Hedgecode. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.hedgecode.chess.pgn.token; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.hedgecode.chess.ParseException; +import org.hedgecode.chess.pgn.entity.Moves; +import org.hedgecode.chess.pgn.nag.Glyph; + +/** + * NAGToken + * + * @author Dmitry Samoshin aka gotty + */ +public class NAGToken implements Token { + + private static final String NAG_REGEX = "^\\s*\\$([0-9]{1,3})"; + private static final Pattern NAG_PATTERN = Pattern.compile(NAG_REGEX); + private static final int NAG_GROUP = 1; + + @Override + public int token(Moves moves, String pgn) throws ParseException { + Matcher matcher = NAG_PATTERN.matcher(pgn); + if (!matcher.find()) { + throw new ParseException("parse.pgn.incorrect.nag", pgn); + } else { + Glyph glyph = Glyph.byNumber( + Integer.parseInt( + matcher.group(NAG_GROUP) + ) + ); + if (glyph != null) { + moves.currentMove().addGlyph(glyph); + } + } + return matcher.group().length(); + } + +} diff --git a/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/ReservedToken.java b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/ReservedToken.java new file mode 100644 index 0000000..f36aa36 --- /dev/null +++ b/chesshog-format/src/main/java/org/hedgecode/chess/pgn/token/ReservedToken.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018-2020. Developed by Hedgecode. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.hedgecode.chess.pgn.token; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.hedgecode.chess.ParseException; +import org.hedgecode.chess.pgn.entity.Moves; + +/** + * ReservedToken + * + * @author Dmitry Samoshin aka gotty + */ +public class ReservedToken implements Token { + + private static final String RESERVED_REGEX = "^\\s*<([^>]+)>"; + private static final Pattern RESERVED_PATTERN = Pattern.compile(RESERVED_REGEX); + + @Override + public int token(Moves moves, String pgn) throws ParseException { + Matcher matcher = RESERVED_PATTERN.matcher(pgn); + if (!matcher.find()) { + throw new ParseException("parse.pgn.incorrect.reserved", pgn); + } + return matcher.group().length(); + } + +} diff --git a/chesshog-format/src/main/resources/org/hedgecode/chess/LocalStrings.properties b/chesshog-format/src/main/resources/org/hedgecode/chess/LocalStrings.properties index 03550db..328db78 100644 --- a/chesshog-format/src/main/resources/org/hedgecode/chess/LocalStrings.properties +++ b/chesshog-format/src/main/resources/org/hedgecode/chess/LocalStrings.properties @@ -26,12 +26,14 @@ parse.pgn.incorrect.tag=Incorrect PGN tag parse.pgn.missed.empty=Missed PGN empty line parse.pgn.incorrect.empty=Incorrect PGN empty line parse.pgn.incorrect.move=Incorrect PGN move +parse.pgn.incorrect.nag=Incorrect NAG of PGN move parse.pgn.incorrect.comment=Incorrect PGN comment parse.pgn.incorrect.variation=Incorrect PGN variation parse.pgn.incorrect.result=Incorrect PGN result parse.pgn.symbols.after.result=Incorrect symbols after PGN result parse.pgn.result.not.match=Result in PGN tags and moves does not match parse.pgn.variation.result=Variations cannot contain PGN result +parse.pgn.incorrect.reserved=Incorrect PGN reserved token parse.tcd.index.out.of.bounds=Array Index Out Of Bounds parse.tcd.invalid.bytes=Invalid input bytes diff --git a/chesshog-format/src/main/resources/org/hedgecode/chess/LocalStrings_ru.properties b/chesshog-format/src/main/resources/org/hedgecode/chess/LocalStrings_ru.properties index 2b913d5..2ac5808 100644 --- a/chesshog-format/src/main/resources/org/hedgecode/chess/LocalStrings_ru.properties +++ b/chesshog-format/src/main/resources/org/hedgecode/chess/LocalStrings_ru.properties @@ -25,12 +25,14 @@ parse.pgn.incorrect.tag= parse.pgn.missed.empty= parse.pgn.incorrect.empty= parse.pgn.incorrect.move= +parse.pgn.incorrect.nag= parse.pgn.incorrect.comment= parse.pgn.incorrect.variation= parse.pgn.incorrect.result= parse.pgn.symbols.after.result= parse.pgn.result.not.match= parse.pgn.variation.result= +parse.pgn.incorrect.reserved= parse.tcd.index.out.of.bounds= parse.tcd.invalid.bytes=