diff --git a/libwccl/CMakeLists.txt b/libwccl/CMakeLists.txt index 7c77e0a346869b6b5e5d462582f78d203473939a..a763a8f4b7241e647a0216c7d0ed1daa91aacc75 100644 --- a/libwccl/CMakeLists.txt +++ b/libwccl/CMakeLists.txt @@ -67,7 +67,9 @@ SET(libwccl_STAT_SRC ops/functions/tset/catfilter.cpp ops/functions/tset/getsymbols.cpp ops/functions/tset/getsymbolsinrange.cpp + ops/match/actions/markbase.cpp ops/match/actions/markmatch.cpp + ops/match/actions/overwritematch.cpp ops/match/actions/unmarkmatch.cpp ops/match/applyoperator.cpp ops/match/conditions/conjconditions.cpp diff --git a/libwccl/ops/match/actions/markbase.cpp b/libwccl/ops/match/actions/markbase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f38d9e32c12df856c0420291eaa4bfd147f4ec20 --- /dev/null +++ b/libwccl/ops/match/actions/markbase.cpp @@ -0,0 +1,109 @@ +#include <libwccl/values/match.h> +#include <libwccl/ops/match/actions/markmatch.h> + +#include <sstream> + + +namespace Wccl { +namespace Matching { + +void MarkBase::execute_mark(const ActionExecContext& context, + bool may_overwrite) const +{ + // TODO may overwrite, use it in mark_mark and perhaps move fields back to private + SentenceContext& sc = context.sentence_context(); + boost::shared_ptr<Corpus2::AnnotatedSentence> as; + as = boost::dynamic_pointer_cast<Corpus2::AnnotatedSentence>(sc.get_sentence_ptr()); + if (!as) { + throw InvalidArgument("context", "Operator needs an annotated sentence."); + } + + boost::shared_ptr<const Match> match_from = match_from_->apply(context); + boost::shared_ptr<const Match> match_to = + (match_from_ == match_to_) ? match_from : match_to_->apply(context); + boost::shared_ptr<const Match> head_match = + (match_from_ == head_match_) ? match_from : head_match_->apply(context); + + int abs_left = match_from->first_token(as); + if (abs_left < 0) { + throw WcclError("Received starting match that points outside sentence."); + } + + int abs_right = match_to->last_token(as); + if (abs_right >= sc.size()) { + throw WcclError("Received ending match that points outside sentence."); + } + if (abs_left > abs_right) { + throw WcclError("Received starting match points after the received ending match."); + } + + int abs_head = head_match->first_token(as); + if (abs_head < abs_left || abs_head > abs_right) { + throw WcclError("Received head match points outside range defined by start and end matches."); + } + + if (!as->has_channel(chan_name_)) { + as->create_channel(chan_name_); + } + Corpus2::AnnotationChannel& channel = as->get_channel(chan_name_); + + int segment_idx = channel.get_new_segment_index(); + + if (may_overwrite) { + std::set<int> segments_to_unmark; + for (int i = abs_left; i <= abs_right; ++i) { + if (channel.get_segment_at(i) > 0) { + segments_to_unmark.insert(channel.get_segment_at(i)); + } + } + if (!segments_to_unmark.empty()) { + // unmark all the segments that appeared within the range + for (int i = 0; i < channel.size(); ++i) { + if (segments_to_unmark.find(channel.segments()[i]) != + segments_to_unmark.end()) { + channel.set_segment_at(i, 0); + channel.set_head_at(i, false); + } + } + } + } + else { + for (int i = abs_left; i <= abs_right; ++i) { + if (channel.get_segment_at(i) > 0) { + throw WcclError("Mark action would overwrite existing annotation"); + } + } + } + // mark new one + for (int i = abs_left; i <= abs_right; ++i) { + channel.set_segment_at(i, segment_idx); + channel.set_head_at(i, false); + } + channel.set_head_at(abs_head, true); +} + +std::string MarkBase::to_string(const Corpus2::Tagset& tagset) const +{ + std::ostringstream os; + os << name() << "(" + << match_from_->to_string(tagset) << ", "; + if (match_from_.get() != match_to_.get()) { + os << match_to_->to_string(tagset) << ", "; + } + os << "\"" << chan_name_ << "\")"; + return os.str(); +} + +std::ostream& MarkBase::write_to(std::ostream& os) const +{ + os << name() << "(" + << *match_from_ << ", "; + if (match_from_.get() != match_to_.get()) { + os << *match_to_ << ", "; + } + os << "\"" << chan_name_ << "\")"; + return os; +} + +} /* end ns Matching */ +} /* end ns Wccl */ diff --git a/libwccl/ops/match/actions/markbase.h b/libwccl/ops/match/actions/markbase.h new file mode 100644 index 0000000000000000000000000000000000000000..dfbedf082714eab907203f0ef4d5c8d7a29525b5 --- /dev/null +++ b/libwccl/ops/match/actions/markbase.h @@ -0,0 +1,63 @@ +#ifndef LIBWCCL_OPS_MATCH_ACTIONS_MARKBASE_H +#define LIBWCCL_OPS_MATCH_ACTIONS_MARKBASE_H + + +#include <libwccl/ops/match/matchaction.h> +#include <libwccl/ops/function.h> + +namespace Wccl { +namespace Matching { + +class MarkBase : public MatchAction +{ +public: + MarkBase( + const boost::shared_ptr<Function<Match> >& match_from, + const boost::shared_ptr<Function<Match> >& match_to, + const boost::shared_ptr<Function<Match> >& head_match, + const std::string& annotation_name) + : match_from_(match_from), + match_to_(match_to), + head_match_(head_match), + chan_name_(annotation_name) + { + BOOST_ASSERT(match_from_); + BOOST_ASSERT(match_to_); + BOOST_ASSERT(head_match_); + } + + virtual std::string name() const = 0; + + /** + * Executes the action for the given execution context. + */ + virtual void execute(const ActionExecContext& context) const = 0; + + std::string to_string(const Corpus2::Tagset& tagset) const; + +protected: + const boost::shared_ptr<Function<Match> > match_from_; + const boost::shared_ptr<Function<Match> > match_to_; + const boost::shared_ptr<Function<Match> > head_match_; + const std::string chan_name_; + + /** + * Writes string representation of the MatchAction to + * an output stream. + * @returns Stream written to. + * @note May be incomplete and/or containt internal info. + */ + virtual std::ostream& write_to(std::ostream& ostream) const; + + /** + * The actual implementation. Depending on may_overwrite, will either + * remove any previous annotations in the range given or will raise + * an exception if any annotations present. */ + void execute_mark(const ActionExecContext& context, bool may_overwrite) + const; +}; + +} /* end ns Matching */ +} /* end ns Wccl */ + +#endif // LIBWCCL_OPS_MATCH_ACTIONS_MARKBASE_H diff --git a/libwccl/ops/match/actions/markmatch.cpp b/libwccl/ops/match/actions/markmatch.cpp index 2a113abf7de17c32a95ea3227d54e1de5d867775..9674af88ebbcecf3ccbdcac8e8dfb314b7b6e62f 100644 --- a/libwccl/ops/match/actions/markmatch.cpp +++ b/libwccl/ops/match/actions/markmatch.cpp @@ -1,4 +1,3 @@ -#include <libwccl/values/match.h> #include <libwccl/ops/match/actions/markmatch.h> #include <sstream> @@ -9,77 +8,8 @@ namespace Matching { void MarkMatch::execute(const ActionExecContext& context) const { - SentenceContext& sc = context.sentence_context(); - boost::shared_ptr<Corpus2::AnnotatedSentence> as; - as = boost::dynamic_pointer_cast<Corpus2::AnnotatedSentence>(sc.get_sentence_ptr()); - if (!as) { - throw InvalidArgument("context", "Operator needs an annotated sentence."); - } - - boost::shared_ptr<const Match> match_from = match_from_->apply(context); - boost::shared_ptr<const Match> match_to = - (match_from_ == match_to_) ? match_from : match_to_->apply(context); - boost::shared_ptr<const Match> head_match = - (match_from_ == head_match_) ? match_from : head_match_->apply(context); - - int abs_left = match_from->first_token(as); - if (abs_left < 0) { - throw WcclError("Received starting match that points outside sentence."); - } - - int abs_right = match_to->last_token(as); - if (abs_right >= sc.size()) { - throw WcclError("Received ending match that points outside sentence."); - } - if (abs_left > abs_right) { - throw WcclError("Received starting match points after the received ending match."); - } - - int abs_head = head_match->first_token(as); - if (abs_head < abs_left || abs_head > abs_right) { - throw WcclError("Received head match points outside range defined by start and end matches."); - } - - if (!as->has_channel(chan_name_)) { - as->create_channel(chan_name_); - } - Corpus2::AnnotationChannel& channel = as->get_channel(chan_name_); - - int segment_idx = channel.get_new_segment_index(); - - for (int i = abs_left; i <= abs_right; ++i) { - if (channel.get_segment_at(i) > 0) { - throw WcclError("Mark action would overwrite existing annotation"); - } - } - for (int i = abs_left; i <= abs_right; ++i) { - channel.set_segment_at(i, segment_idx); - channel.set_head_at(i, false); - } - channel.set_head_at(abs_head, true); -} - -std::string MarkMatch::to_string(const Corpus2::Tagset& tagset) const -{ - std::ostringstream os; - os << name() << "(" - << match_from_->to_string(tagset) << ", "; - if (match_from_.get() != match_to_.get()) { - os << match_to_->to_string(tagset) << ", "; - } - os << "\"" << chan_name_ << "\")"; - return os.str(); -} - -std::ostream& MarkMatch::write_to(std::ostream& os) const -{ - os << name() << "(" - << *match_from_ << ", "; - if (match_from_.get() != match_to_.get()) { - os << *match_to_ << ", "; - } - os << "\"" << chan_name_ << "\")"; - return os; + // fire inner execute in fail-on-annotation-overwrite mode + execute_mark(context, false); } } /* end ns Matching */ diff --git a/libwccl/ops/match/actions/markmatch.h b/libwccl/ops/match/actions/markmatch.h index 514ec19e8c05358068a906a5b247424567d7994a..3f1cd3d8721c04afb2abeec099e71cab3719a532 100644 --- a/libwccl/ops/match/actions/markmatch.h +++ b/libwccl/ops/match/actions/markmatch.h @@ -1,13 +1,12 @@ #ifndef LIBWCCL_OPS_MATCH_ACTIONS_MARKMATCH_H #define LIBWCCL_OPS_MATCH_ACTIONS_MARKMATCH_H -#include <libwccl/ops/match/matchaction.h> -#include <libwccl/ops/function.h> +#include <libwccl/ops/match/actions/markbase.h> namespace Wccl { namespace Matching { -class MarkMatch : public MatchAction +class MarkMatch : public MarkBase { public: MarkMatch( @@ -15,42 +14,25 @@ public: const boost::shared_ptr<Function<Match> >& match_to, const boost::shared_ptr<Function<Match> >& head_match, const std::string& annotation_name) - : match_from_(match_from), - match_to_(match_to), - head_match_(head_match), - chan_name_(annotation_name) + : MarkBase(match_from, match_to, head_match, annotation_name) { - BOOST_ASSERT(match_from_); - BOOST_ASSERT(match_to_); - BOOST_ASSERT(head_match_); } MarkMatch( const boost::shared_ptr<Function<Match> >& match_from, const boost::shared_ptr<Function<Match> >& match_to, const std::string& annotation_name) - : match_from_(match_from), - match_to_(match_to), - head_match_(match_from), - chan_name_(annotation_name) + : MarkBase(match_from, match_to, match_from, annotation_name) { - BOOST_ASSERT(match_from_); - BOOST_ASSERT(match_to_); - BOOST_ASSERT(head_match_); } MarkMatch( const boost::shared_ptr<Function<Match> >& match_from_to, const std::string& annotation_name) - : match_from_(match_from_to), - match_to_(match_from_to), - head_match_(match_from_to), - chan_name_(annotation_name) + : MarkBase(match_from_to, match_from_to, match_from_to, annotation_name) { - BOOST_ASSERT(match_from_); - BOOST_ASSERT(match_to_); - BOOST_ASSERT(head_match_); } + /** * @returns Name of the action. */ @@ -62,25 +44,6 @@ public: * Executes the action for the given execution context. */ void execute(const ActionExecContext& context) const; - - /** - * @returns String representation of the expression. - */ - std::string to_string(const Corpus2::Tagset& tagset) const; - -protected: - /** - * Writes string representation of the MatchAction to - * an output stream. - * @returns Stream written to. - * @note May be incomplete and/or containt internal info. - */ - virtual std::ostream& write_to(std::ostream& ostream) const; -private: - const boost::shared_ptr<Function<Match> > match_from_; - const boost::shared_ptr<Function<Match> > match_to_; - const boost::shared_ptr<Function<Match> > head_match_; - const std::string chan_name_; }; } /* end ns Matching */ diff --git a/libwccl/ops/match/actions/overwritematch.cpp b/libwccl/ops/match/actions/overwritematch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8fafa7bef924dd6aadced33d5a56332d2f17fe9 --- /dev/null +++ b/libwccl/ops/match/actions/overwritematch.cpp @@ -0,0 +1,16 @@ +#include <libwccl/ops/match/actions/overwritematch.h> + +#include <sstream> + + +namespace Wccl { +namespace Matching { + +void OverwriteMatch::execute(const ActionExecContext& context) const +{ + // fire inner execute in silent-overwrite mode + execute_mark(context, true); +} + +} /* end ns Matching */ +} /* end ns Wccl */ diff --git a/libwccl/ops/match/actions/overwritematch.h b/libwccl/ops/match/actions/overwritematch.h new file mode 100644 index 0000000000000000000000000000000000000000..87dbd2e73e17384c68df851e511e3e1709bb13fe --- /dev/null +++ b/libwccl/ops/match/actions/overwritematch.h @@ -0,0 +1,52 @@ +#ifndef LIBWCCL_OPS_MATCH_ACTIONS_OVERWRITEMATCH_H +#define LIBWCCL_OPS_MATCH_ACTIONS_OVERWRITEMATCH_H + +#include <libwccl/ops/match/actions/markbase.h> + +namespace Wccl { +namespace Matching { + +class OverwriteMatch : public MarkBase +{ +public: + OverwriteMatch( + const boost::shared_ptr<Function<Match> >& match_from, + const boost::shared_ptr<Function<Match> >& match_to, + const boost::shared_ptr<Function<Match> >& head_match, + const std::string& annotation_name) + : MarkBase(match_from, match_to, head_match, annotation_name) + { + } + + OverwriteMatch( + const boost::shared_ptr<Function<Match> >& match_from, + const boost::shared_ptr<Function<Match> >& match_to, + const std::string& annotation_name) + : MarkBase(match_from, match_to, match_from, annotation_name) + { + } + + OverwriteMatch( + const boost::shared_ptr<Function<Match> >& match_from_to, + const std::string& annotation_name) + : MarkBase(match_from_to, match_from_to, match_from_to, annotation_name) + { + } + + /** + * @returns Name of the action. + */ + std::string name() const { + return "remark"; + } + + /** + * Executes the action for the given execution context. + */ + void execute(const ActionExecContext& context) const; +}; + +} /* end ns Matching */ +} /* end ns Wccl */ + +#endif // LIBWCCL_OPS_MATCH_ACTIONS_OVERWRITEMATCH_H diff --git a/libwccl/parser/grammar.g b/libwccl/parser/grammar.g index 5d6e6db82796dda93b800cee6efa802d3f04d0ff..7aa71ed78c8738b6656bcdf1c0f2e8a545564a41 100644 --- a/libwccl/parser/grammar.g +++ b/libwccl/parser/grammar.g @@ -97,6 +97,7 @@ header { #include <libwccl/ops/match/conditions/longest.h> #include <libwccl/ops/match/actions/markmatch.h> #include <libwccl/ops/match/actions/unmarkmatch.h> + #include <libwccl/ops/match/actions/overwritematch.h> #include <libwccl/ops/functions/match/submatch.h> // Wccl whole file syntax @@ -2686,6 +2687,7 @@ match_action returns [boost::shared_ptr<Matching::MatchAction> m_act] : m_act = match_mark_action [scope] | m_act = match_unmark_action [scope] + | m_act = match_remark_action [scope] ; // Match mark action @@ -2748,6 +2750,47 @@ match_unmark_action } ; +// Overwrite-match mark action ("remark") +// Returns +match_remark_action + [ParsingScope& scope] + returns [boost::shared_ptr<Matching::OverwriteMatch> m_act] +{ + boost::shared_ptr<Function<Match> > match_to; + boost::shared_ptr<Function<Match> > match_from; + boost::shared_ptr<Function<Match> > head_match; +} + : "remark" LPAREN + match_from = match_operator[scope] COMMA + ( match_to = match_operator[scope] COMMA + ( head_match = match_operator[scope] COMMA )? + )? + annotation_name : STRING + RPAREN { + if (!match_to) { + m_act.reset( + new Matching::OverwriteMatch( + match_from, + ((antlr::Token*)annotation_name)->getText())); + } else { + if (!head_match) { + m_act.reset( + new Matching::OverwriteMatch( + match_from, + match_to, + ((antlr::Token*)annotation_name)->getText())); + } else { + m_act.reset( + new Matching::OverwriteMatch( + match_from, + match_to, + head_match, + ((antlr::Token*)annotation_name)->getText())); + } + } + } +; + // Match action separated by comma // Returns boost::shared_ptr<std::vector<boost::shared_ptr<Matching::MatchAction> > > match_action_comma_sep diff --git a/tests/rules-data/match/remark/cclmatch.xml b/tests/rules-data/match/remark/cclmatch.xml new file mode 100644 index 0000000000000000000000000000000000000000..25498def4c4f08d429448416989c31e7e70274a0 --- /dev/null +++ b/tests/rules-data/match/remark/cclmatch.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE cesAna SYSTEM "xcesAnaIPI.dtd"> +<chunkList xmlns:xlink="http://www.w3.org/1999/xlink"> + <chunk> + <sentence> + <tok> + <orth>Miasto</orth> + <lex><base>miasto</base><ctag>noun</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P" head="1">1</ann> + </tok> + <tok> + <orth>stołeczne</orth> + <lex><base>stołeczny</base><ctag>adj</ctag></lex> + <ann chan="AdjN" head="1">1</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>Warszawa</orth> + <lex><base>warszawa</base><ctag>noun</ctag></lex> + <ann chan="AdjN">1</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>centralna</orth> + <lex><base>centralny</base><ctag>adj</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P">0</ann> + </tok> + <ns/> + <tok> + <orth>,</orth> + <lex><base>,</base><ctag>interp</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>nowy</orth> + <lex><base>nowy</base><ctag>adj</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P" head="1">2</ann> + </tok> + <tok> + <orth>wielki</orth> + <lex><base>wielki</base><ctag>adj</ctag></lex> + <ann chan="AdjN" head="1">2</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>Berlin</orth> + <lex><base>berlin</base><ctag>noun</ctag></lex> + <ann chan="AdjN">2</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>Zachodni</orth> + <lex><base>zachodni</base><ctag>adj</ctag></lex> + <lex><base>zachodny</base><ctag>adj</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>z</orth> + <lex><base>z</base><ctag>other</ctag></lex> + <lex><base>z</base><ctag>qub</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>dzielnicą</orth> + <lex><base>dzielnica</base><ctag>noun</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>turecką</orth> + <lex><base>turecki</base><ctag>adj</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P">0</ann> + </tok> + <ns/> + <tok> + <orth>.</orth> + <lex><base>.</base><ctag>interp</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P">0</ann> + </tok> + </sentence> + </chunk> +</chunkList> diff --git a/tests/rules-data/match/remark/cclmatch1.ccl b/tests/rules-data/match/remark/cclmatch1.ccl new file mode 100644 index 0000000000000000000000000000000000000000..a207bc81a94c82b31fd0aa77de3f57c199e37826 --- /dev/null +++ b/tests/rules-data/match/remark/cclmatch1.ccl @@ -0,0 +1,25 @@ +match_rules( + apply( + match( + is("P"), + inter(class[0], adj) + ), + actions( + remark( M, "P" ) + ) + ) ; + + + apply( + match( + inter(base[0], ["zachodni"]), + inter(base[0], ["z"]), + inter(base[0], ["dzielnica"]), + inter(base[0], ["turecki"]) + ), + actions( + remark( M, "AdjN" ) + ) + ) + +) diff --git a/tests/rules-data/match/remark/cclmatch1.out.xml b/tests/rules-data/match/remark/cclmatch1.out.xml new file mode 100644 index 0000000000000000000000000000000000000000..2f389b0cb810b8d9b1c08bd05161b3868415ba1c --- /dev/null +++ b/tests/rules-data/match/remark/cclmatch1.out.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE cesAna SYSTEM "xcesAnaIPI.dtd"> +<chunkList xmlns:xlink="http://www.w3.org/1999/xlink"> + <chunk> + <sentence> + <tok> + <orth>Miasto</orth> + <lex><base>miasto</base><ctag>noun</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P" head="1">3</ann> + </tok> + <tok> + <orth>stołeczne</orth> + <lex><base>stołeczny</base><ctag>adj</ctag></lex> + <ann chan="AdjN" head="1">1</ann> + <ann chan="P">3</ann> + </tok> + <tok> + <orth>Warszawa</orth> + <lex><base>warszawa</base><ctag>noun</ctag></lex> + <ann chan="AdjN">1</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>centralna</orth> + <lex><base>centralny</base><ctag>adj</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P">0</ann> + </tok> + <ns/> + <tok> + <orth>,</orth> + <lex><base>,</base><ctag>interp</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>nowy</orth> + <lex><base>nowy</base><ctag>adj</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P" head="1">1</ann> + </tok> + <tok> + <orth>wielki</orth> + <lex><base>wielki</base><ctag>adj</ctag></lex> + <ann chan="AdjN" head="1">2</ann> + <ann chan="P">1</ann> + </tok> + <tok> + <orth>Berlin</orth> + <lex><base>berlin</base><ctag>noun</ctag></lex> + <ann chan="AdjN">2</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>Zachodni</orth> + <lex><base>zachodni</base><ctag>adj</ctag></lex> + <lex><base>zachodny</base><ctag>adj</ctag></lex> + <ann chan="AdjN" head="1">3</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>z</orth> + <lex><base>z</base><ctag>other</ctag></lex> + <lex><base>z</base><ctag>qub</ctag></lex> + <ann chan="AdjN">3</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>dzielnicą</orth> + <lex><base>dzielnica</base><ctag>noun</ctag></lex> + <ann chan="AdjN">3</ann> + <ann chan="P">0</ann> + </tok> + <tok> + <orth>turecką</orth> + <lex><base>turecki</base><ctag>adj</ctag></lex> + <ann chan="AdjN">3</ann> + <ann chan="P">0</ann> + </tok> + <ns/> + <tok> + <orth>.</orth> + <lex><base>.</base><ctag>interp</ctag></lex> + <ann chan="AdjN">0</ann> + <ann chan="P">0</ann> + </tok> + </sentence> + </chunk> +</chunkList> diff --git a/tests/rules-data/match/remark/simple.is-the-tagset b/tests/rules-data/match/remark/simple.is-the-tagset new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/tests/rules-data/match/remark/simple.is-the-tagset @@ -0,0 +1 @@ +