使用PEGTL(https://github.com/taocpp/PEGTL),这是一个基于模板的C++ 11仅限 header 的PEG库,我可以这样定义Unicode字符的范围:

  • utf8::range //所有UTF8字符
  • utf8::range // UTF8 0x41-0x5A [A-Z]和0x61-0x7A [a-z]

  • 现在,使用UTF8,可以使用此属性分类(https://en.wikipedia.org/wiki/Unicode_character_property#General_Category)进行类似[:Lu:]或[:ID_Start:]的操作,并获得一组字符/范围。

    现在,由于我正在使用c++模板,因此在编译时需要这些范围。我认为我有以下选择:
  • 发现PEGTL本身可以查找[:ID_Start:]或[:Lu:]
  • 查找一个c++预处理程序库,该库允许在编译时进行此类查询
  • 获取一个应用程序/在线服务,我可以在其中执行那些查询并获取范围(如上所示),然后可以将其粘贴到我的代码中。

  • 这也代表了我更喜欢的解决方案的顺序。

    最佳答案

    PEGTL使用规则来匹配字符,而不返回字符集。如果您想将字符与某些Unicode字符属性进行匹配,则可以创建custom rule并在某些Unicode库的帮助下实现它,例如ICU。它提供了测试代码点各种属性的方法,请参见this link

    这是一个完整的示例程序:

    #include <iomanip>
    #include <iostream>
    
    #include <unicode/uchar.h>
    
    #include <tao/pegtl.hpp>
    
    using namespace tao::TAO_PEGTL_NAMESPACE;  // NOLINT
    
    namespace test
    {
       template< UProperty P >
       struct icu_has_binary_property
       {
          using analyze_t = analysis::generic< analysis::rule_type::ANY >;
    
          template< typename Input >
          static bool match( Input& in )
          {
             // this assumes the input is UTF8, adapt as necessary
             const auto r = internal::peek_utf8::peek( in );
             // if a code point is available, the size is >0
             if( r.size != 0 ) {
                // check the property
                if( u_hasBinaryProperty( r.data, P ) ) {
                   // if it matches, consume the character
                   in.bump( r.size );
                   return true;
                }
             }
             return false;
          }
       };
    
       using icu_lower = icu_has_binary_property< UCHAR_LOWERCASE >;
       using icu_upper = icu_has_binary_property< UCHAR_UPPERCASE >;
    
       // clang-format off
       struct grammar : seq< icu_upper, plus< icu_lower >, eof > {};
       // clang-format on
    }
    
    int main( int argc, char** argv )
    {
       for( int i = 1; i < argc; ++i ) {
          argv_input<> in( argv, i );
          std::cout << argv[ i ] << " matches: " << std::boolalpha << parse< test::grammar >( in ) << std::endl;
       }
    }
    

    现在,我可以编译并运行它:

    $ g++ -std=c++11 -pedantic -Wall -Wextra -Werror -O3 -Ipegtl/include icu.cpp -licuuc -licudata -o icu
    $ ./icu Ďánîel DánÎel
    Ďánîel matches: true
    DánÎel matches: false
    $
    

    编辑:我已经将ICU rules(很多)添加到了PEGTL中。由于它们需要ICU(外部依赖项),因此将它们放在contrib -section中。

    09-05 06:40