Rcpp Version 1.0.9
trimws.h
Go to the documentation of this file.
1 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 //
3 // trimws.h: Rcpp R/C++ interface class library -- trimws
4 //
5 // Copyright (C) 2017 Nathan Russell
6 //
7 // This file is part of Rcpp.
8 //
9 // Rcpp is free software: you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Rcpp is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
21 
22 #ifndef Rcpp__sugar__trimws_h
23 #define Rcpp__sugar__trimws_h
24 
25 #include <string>
26 #include <cstring>
27 
28 namespace Rcpp {
29 namespace sugar {
30 namespace detail {
31 
32 
33 /* NB: std::isspace is not used because it also counts
34  '\f' and '\v' as whitespace, whereas base::trimws only
35  checks for ' ', '\t', '\r', and '\n' */
36 inline bool isws(const char c) {
37  return c == ' ' || c == '\t' || c == '\n' || c == '\r';
38 }
39 
40 inline const char* trim_left(const char* str) {
41  if (!str) {
42  return "";
43  }
44 
45  while (isws(*str)) {
46  ++str;
47  }
48 
49  return str;
50 }
51 
52 inline const char* trim_right(const char* str, R_len_t sz, std::string* buff) {
53  if (!str) {
54  return "";
55  }
56 
57  buff->clear();
58  const char* ptr = str + sz - 1;
59 
60  for (; ptr > str && isws(*ptr); --sz, --ptr);
61 
62  buff->append(str, sz - isws(*ptr));
63  return buff->c_str();
64 }
65 
66 inline const char* trim_both(const char* str, R_len_t sz, std::string* buff) {
67  if (!str) {
68  return "";
69  }
70 
71  buff->clear();
72 
73  while (isws(*str)) {
74  ++str; --sz;
75  }
76 
77  const char* ptr = str + sz - 1;
78 
79  for (; ptr > str && isws(*ptr); --sz, --ptr);
80 
81  buff->append(str, sz);
82  return buff->c_str();
83 }
84 
85 
86 } // detail
87 } // sugar
88 
89 
90 inline Vector<STRSXP> trimws(const Vector<STRSXP>& x, const char* which = "both") {
91  R_xlen_t i = 0, sz = x.size();
92  Vector<STRSXP> res = no_init(sz);
93  std::string buffer;
94 
95  if (*which == 'b') {
96  for (; i < sz; i++) {
97  if (traits::is_na<STRSXP>(x[i])) {
98  res[i] = x[i];
99  } else {
100  res[i] = sugar::detail::trim_both(
101  x[i],
102  LENGTH(x[i]),
103  &buffer
104  );
105  }
106  }
107  } else if (*which == 'l') {
108  for (; i < sz; i++) {
109  if (traits::is_na<STRSXP>(x[i])) {
110  res[i] = x[i];
111  } else {
112  res[i] = sugar::detail::trim_left(x[i]);
113  }
114  }
115  } else if (*which == 'r') {
116  for (; i < sz; i++) {
117  if (traits::is_na<STRSXP>(x[i])) {
118  res[i] = x[i];
119  } else {
120  res[i] = sugar::detail::trim_right(
121  x[i],
122  LENGTH(x[i]),
123  &buffer
124  );
125  }
126  }
127  } else {
128  stop("Invalid `which` argument '%s'!", which);
129  return Vector<STRSXP>::create("Unreachable");
130  }
131 
132  return res;
133 }
134 
135 inline Matrix<STRSXP> trimws(const Matrix<STRSXP>& x, const char* which = "both") {
136  R_xlen_t i = 0, sz = x.size();
137  int nr = x.nrow(), nc = x.ncol();
138  Matrix<STRSXP> res = no_init(nr, nc);
139  std::string buffer;
140 
141  if (*which == 'b') {
142  for (; i < sz; i++) {
143  if (traits::is_na<STRSXP>(x[i])) {
144  res[i] = x[i];
145  } else {
146  res[i] = sugar::detail::trim_both(
147  x[i],
148  LENGTH(x[i]),
149  &buffer
150  );
151  }
152  }
153  } else if (*which == 'l') {
154  for (; i < sz; i++) {
155  if (traits::is_na<STRSXP>(x[i])) {
156  res[i] = x[i];
157  } else {
158  res[i] = sugar::detail::trim_left(x[i]);
159  }
160  }
161  } else if (*which == 'r') {
162  for (; i < sz; i++) {
163  if (traits::is_na<STRSXP>(x[i])) {
164  res[i] = x[i];
165  } else {
166  res[i] = sugar::detail::trim_right(
167  x[i],
168  LENGTH(x[i]),
169  &buffer
170  );
171  }
172  }
173  } else {
174  stop("Invalid `which` argument '%s'!", which);
175  return Matrix<STRSXP>();
176  }
177 
178  return res;
179 }
180 
181 inline String trimws(const String& str, const char* which = "both") {
182  std::string buffer;
183 
184  if (*which == 'b') {
185  if (traits::is_na<STRSXP>(str.get_sexp())) {
186  return String(str.get_sexp());
187  }
189  str.get_cstring(),
190  LENGTH(str.get_sexp()),
191  &buffer
192  );
193  }
194 
195  if (*which == 'l') {
196  if (traits::is_na<STRSXP>(str.get_sexp())) {
197  return String(str.get_sexp());
198  }
200  }
201 
202  if (*which == 'r') {
203  if (traits::is_na<STRSXP>(str.get_sexp())) {
204  return String(str.get_sexp());
205  }
207  str.get_cstring(),
208  LENGTH(str.get_sexp()),
209  &buffer
210  );
211  }
212 
213  stop("Invalid `which` argument '%s'!", which);
214  return String("Unreachable");
215 }
216 
217 
218 } // Rcpp
219 
220 #endif // Rcpp__sugar__trimws_h
int ncol() const
Definition: Matrix.h:94
int nrow() const
Definition: Matrix.h:97
const char * get_cstring() const
Definition: String.h:576
SEXP get_sexp() const
Definition: String.h:557
R_xlen_t size() const
Definition: Vector.h:276
static Vector create()
Definition: Vector.h:1122
const char * trim_right(const char *str, R_len_t sz, std::string *buff)
Definition: trimws.h:52
bool isws(const char c)
Definition: trimws.h:36
const char * trim_left(const char *str)
Definition: trimws.h:40
const char * trim_both(const char *str, R_len_t sz, std::string *buff)
Definition: trimws.h:66
bool is_na< STRSXP >(SEXP x)
Definition: is_na.h:52
Rcpp API.
Definition: algo.h:28
no_init_vector no_init(R_xlen_t size)
Definition: no_init.h:77
void NORET stop(const char *fmt, Args &&... args)
Definition: exceptions.h:51
Vector< STRSXP > trimws(const Vector< STRSXP > &x, const char *which="both")
Definition: trimws.h:90