2015-07-19 23 views
5

Chociaż może z powodzeniem rodzaj hiszpańskiego słowa z akcentowanych samogłosek, określając UTF-8 w std :: sortowaniaSortuj mapie (hiszpański) akcentowane słowa RCPP

// [[Rcpp::export]] 
std::vector<std::string> sort_words(std::vector<std::string> x) { 
    std::sort(x.begin(), x.end(), std::locale("en_US.UTF-8")); 
    return x; 
} 

/*** R 
words <- c("casa", "árbol", "zona", "árbol", "casa", "libro") 
sort_words(words) 
*/ 

returns (as expected): 
[1] "árbol" "árbol" "casa" "casa" "libro" "zona" 

nie mogę dowiedzieć się, jak zrobić to samo z mapą:

// slightly modified version of tableC on http://adv-r.had.co.nz/Rcpp.html 
// [[Rcpp::export]] 
std::map<String, int> table_words(CharacterVector x) { 
    std::setlocale(LC_ALL, "en_US.UTF-8"); 
    // std::setlocale(LC_COLLATE, "en_US.UTF-8"); // also tried this instead of previous line 
    std::map<String, int> counts; 
    int n = x.size(); 
    for (int i = 0; i < n; i++) { 
    counts[x[i]]++; 
    } 
    return counts; 
} 

/*** R 
words <- c("casa", "árbol", "zona", "árbol", "casa", "libro") 
table_words(words) 
*/ 

returns: 
casa libro zona árbol 
    2  1  1  2 

but I want: 
árbol casa libro zona  
    2  2  1  1 

Wszelkie pomysły, w jaki sposób mają table_words umieścić akcentowane „Arbol” przed „casa”, z RCPP lub nawet wycofać się w badania, z base::sort?

Także, tylko słowa na mojej maszynie Linux z: gcc wersja 4.8.2 (Ubuntu 4.8.2-19ubuntu1). Nie działa na komputerze Mac 10.10.3 z: Apple LLVM wersja 6.1.0 (clang-602.0.53) (na podstawie LLVM 3.6.0svn). Jakieś wskazówki dotyczące kompilatora mojego Maca, którego brakuje w moim kompilatorze?

Oto mój skrypt i mój sessionInfo, na obu komputerach:

// [[Rcpp::plugins(cpp11)]] 
#include <locale> 
#include <clocale> 
#include <Rcpp.h> 
using namespace Rcpp; 

// [[Rcpp::export]] 
std::vector<std::string> sort_words(std::vector<std::string> x) { 
    std::sort(x.begin(), x.end(), std::locale("en_US.UTF-8")); 
    return x; 
} 

// [[Rcpp::export]] 
std::map<String, int> table_words(CharacterVector x) { 
    // std::setlocale(LC_ALL, "en_US.UTF-8"); // tried this instead of next line 
    std::setlocale(LC_COLLATE, "en_US.UTF-8"); 
    std::map<String, int> counts; 
    int n = x.size(); 
    for (int i = 0; i < n; i++) { 
    counts[x[i]]++; 
    } 
    return counts; 
} 

/*** R 
words <- c("casa", "árbol", "zona", "árbol", "casa", "libro") 
sort_words(words) 
table_words(words) 
sort(table_words(words), decreasing = T) 
output_from_Rcpp <- table_words(words) 
sort(names(output_from_Rcpp)) 
*/ 

> words <- c("casa", "árbol", "zona", "árbol", "casa", "libro") 

> sort_words(words) 
[1] "árbol" "árbol" "casa" "casa" "libro" "zona" 

> table_words(words) 
casa libro zona árbol 
    2  1  1  2 

> sort(table_words(words), decreasing = T) 
casa árbol libro zona 
    2  2  1  1 

> output_from_Rcpp <- table_words(words) 

> sort(names(output_from_Rcpp)) 
[1] "árbol" "casa" "libro" "zona" 

sessionInfo on linux machine: 
R version 3.2.0 (2015-04-16) 
Platform: x86_64-pc-linux-gnu (64-bit) 
Running under: Ubuntu 14.04 LTS 

locale: 
[1] en_US.UTF-8 

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

loaded via a namespace (and not attached): 
[1] tools_3.2.0 Rcpp_0.11.6 

sessionInfo on Mac: 
R version 3.2.1 (2015-06-18) 
Platform: x86_64-apple-darwin13.4.0 (64-bit) 
Running under: OS X 10.10.3 (Yosemite) 

locale: 
[1] en_US.UTF-8 

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

other attached packages: 
[1] textcat_1.0-3 readr_0.1.1 rvest_0.2.0 

loaded via a namespace (and not attached): 
[1] httr_1.0.0 selectr_0.2-3 R6_2.1.0  magrittr_1.5 tools_3.2.1 curl_0.9.1 Rcpp_0.11.6 slam_0.1-32 stringi_0.5-5 
[10] tau_0.0-18 stringr_1.0.0 XML_3.98-1.3 
+1

Pardon moja ignorancja, ale kiedy to 'std :: sort' wziąć trzeci parametr, który był narodowe? Trzeci parametr dla 'std :: sort' ma być funkcją lub functorem, który porównuje dwa elementy, a nie locale. – PaulMcKenzie

+1

@PaulMcKenzie: Locale to między innymi funktor, który porównuje dwa elementy. http://pl.cppreference.com/w/cpp/locale/locale/operator() –

+1

Nie wiem nic na temat "Rcpp", ale czy wiesz, że dla 'std :: map', zamówienie jest częścią sam typ i czy potrzebujesz niestandardowego komparatora, aby włączyć inne zamówienie? –

Odpowiedz

1

To nie ma sensu stosować std::sort na std::map, ponieważ mapa jest zawsze klasyfikowane, z definicji. Ta definicja jest częścią konkretnego typu tworzonego przez szablon. std::map ma trzeci, "ukryty" parametr typu dla funkcji porównania używanej do zamawiania kluczy, która domyślnie przyjmuje wartość std::less dla typu klucza. Zobacz http://en.cppreference.com/w/cpp/container/map.

W twoim przypadku możesz użyć std::locale jako typu porównania i przekazać std::locale("en-US") (lub cokolwiek innego, co pasuje do twojego systemu) do konstruktora.

Oto przykład. Używa C++ 11, ale możesz łatwo użyć tego samego rozwiązania w C++ 03.

#include <map> 
#include <iostream> 
#include <string> 
#include <locale> 
#include <exception> 

using Map = std::map<std::string, int, std::locale>; 

int main() 
{ 
    try 
    { 
     Map map(std::locale("en-US")); 
     map["casa"] = 1; 
     map["árbol"] = 2; 
     map["zona"] = 3; 
     map["árbol"] = 4; 
     map["casa"] = 5; 
     map["libro"] = 6; 

     for (auto const& map_entry : map) 
     { 
      std::cout << map_entry.first << " -> " << map_entry.second << "\n"; 
     } 
    } 
    catch (std::exception const& exc) 
    { 
     std::cerr << exc.what() << "\n"; 
    } 
} 

wyjściowa:

árbol -> 4 
casa -> 5 
libro -> 6 
zona -> 3 

Oczywiście, trzeba zdawać sobie sprawę z faktu, że std::locale jest wysoce zależna od implementacji. Możesz być lepiej z Boost.Locale.

Innym problemem jest to, że to rozwiązanie może wyglądać na zagmatwane, ponieważ std::locale nie jest dokładnie czymś, co wielu programistów kojarzy z funkcją porównania. To prawie zbyt sprytne.

Stąd być może bardziej czytelna alternatywa:

#include <map> 
#include <iostream> 
#include <string> 
#include <locale> 
#include <exception> 

struct ComparisonUsingLocale 
{ 
    std::locale locale{ "en-US" }; 

    bool operator()(std::string const& lhs, std::string const& rhs) const 
    { 
     return locale(lhs, rhs); 
    } 
}; 

using Map = std::map<std::string, int, ComparisonUsingLocale>; 

int main() 
{ 
    try 
    { 
     Map map; 
     map["casa"] = 1; 
     map["árbol"] = 2; 
     map["zona"] = 3; 
     map["árbol"] = 4; 
     map["casa"] = 5; 
     map["libro"] = 6; 

     for (auto const& map_entry : map) 
     { 
      std::cout << map_entry.first << " -> " << map_entry.second << "\n"; 
     } 
    } 
    catch (std::exception const& exc) 
    { 
     std::cerr << exc.what() << "\n"; 
    } 
} 
+0

Dzięki za przedłużoną pomoc, ale wciąż nie ma szczęścia: Earls-MBP: C++ earlbrown $ 'g ++ -std = C++ 11 order_with_accents.cpp -o go' Earls-MBP: C++ earlbrown $'./Go' 'collate_byname :: collate_byname nie udało się skonstruować dla en-US' Earls-MBP: C++ earlbrown $' g ++ -v' 'Konfiguracja z: --prefix =/Applications/Xcode.app/Contents/Developer/usr - z-gxx-include-dir =/usr/include/C++/4.2.1 Apple LLVM wersja 6.1.0 (clang-602.0.53) (w oparciu o LLVM 3.6.0svn) Target: x86_64-apple-darwin14.4.0 Model gwintu: posix' –