PEBL 2.2
Psychology Experiment Building Language - Cross-platform psychological experiment development system
PEBLString.cpp
Go to the documentation of this file.
1//* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
3// Name: src/libs/PEBLString.cpp
4// Purpose: String Processing Function Library for PEBL
5// Author: Shane T. Mueller, Ph.D.
6// Copyright: (c) 2004-2026 Shane T. Mueller <smueller@obereed.net>
7// License: GPL 2
8//
9//
10//
11// This file is part of the PEBL project.
12//
13// PEBL is free software; you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation; either version 2 of the License, or
16// (at your option) any later version.
17//
18// PEBL is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with PEBL; if not, write to the Free Software
25// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27#include "PEBLString.h"
28#include "../base/Variant.h"
29#include "../base/PComplexData.h"
30#include "../base/PList.h"
31
32#include "../utility/PEBLUtility.h"
33#include "../utility/PError.h"
34
35extern "C" {
36#include "../utility/re.h"
37}
38
39#include <string>
40#include <vector>
41#include <algorithm>
42#include <iostream>
43#include <cctype>
44
45using std::ostream;
46using std::cerr;
47using std::endl;
48using std::list;
49using std::string;
50
51#ifdef PEBL_EMSCRIPTEN
52#include "../platforms/sdl/PlatformEnvironment.h"
54#elif defined(PEBL_VALIDATOR)
55#include "../platforms/validator/PlatformEnvironment.h"
57#else
58#include "../platforms/sdl/PlatformEnvironment.h"
60#endif
61
62
63
64
66{
67
68 //v[1] should have the parameter: a list of keys to wait for.
69 PList * plist = v.GetComplexData()->GetList();
70
71 PError::AssertType(plist->First(), PEAT_STRING, "Argument error in function Uppercase(<string>)]: ");
72
73 std::string s=plist->First();
74 transform(s.begin(), s.end(), s.begin(), toupper);
75
76 return Variant(s);
77}
78
79
80
82{
83
84 //v[1] should have the parameter: a list of keys to wait for.
85 PList * plist = v.GetComplexData()->GetList();
86 PError::AssertType(plist->First(), PEAT_STRING, "Argument error in function Uppercase(<string>)]: ");
87
88 std::string s=plist->First();
89 transform(s.begin(), s.end(), s.begin(), tolower);
90
91 return Variant(s);
92}
93
94
96{
97
98 PList * plist = v.GetComplexData()->GetList();
99 PError::AssertType(plist->First(), PEAT_INTEGER, "Argument error in function ToASCII(<integer>)]: ");
100
101 std::string s = "";
102 s[0] = (plist->First()).GetInteger();
103
104 return Variant((std::string(s)));
105
106}
107
108
110{
111
112 //v[1] should have the parameter: a list of keys to wait for.
113 PList * plist = v.GetComplexData()->GetList();
114 PError::AssertType(plist->First(), PEAT_STRING, "Argument error in function StringLength(<string>)]: ");
115 std::string s=plist->First();
116
117 return Variant((int)(s.length()));
118}
119
120
121//Not implemented:
122#if 0
123Variant PEBLString::Strip(Variant v)
124{
125
126 //v[1] should have the parameter: a list of keys to wait for.
127 PList * plist = v.GetComplexData()->GetList();
128 PError::AssertType(plist->First(), PEAT_STRING, "Argument error in function StringLength(<string>)]: ");
129 std::string s=plist->First();
130
131 return Variant((int)(s.length()));
132}
133#endif
134
136{
137
138 //v[1] should have the parameter: a list of keys to wait for.
139 PList * plist = v.GetComplexData()->GetList();
140
141 PError::AssertType(plist->First(), PEAT_STRING, "Argument error in first parameter of function SubString(<string>, <index>, <length>)]: ");
142 std::string string1 = plist->First(); //plist->PopFront();
143
144 PError::AssertType(plist->Nth(2), PEAT_INTEGER, "Argument error in Second parameter of function SubString(<string>, <index>, <length>)]: ");
145 int position = plist->Nth(2);// plist->PopFront();
146
147 PError::AssertType(plist->Nth(3), PEAT_INTEGER, "Argument error in Third parameter of function SubString(<string>, <index>, <length>)]: ");
148 int length = plist->Nth(3);// plist->PopFront();
149
150 if(position < 1)
151 {
152 PError::SignalFatalError("Trying to get substring with index less than 1");
153 }
154 if(string1.length()<position)
155 {
156 PError::SignalFatalError("Trying to get substring with index longer than string");
157 }
158 //cout << "Length: " << string1.length() << "pos: " << position << "len1:"<< length << endl;
159 if(string1.length() < position-1+length)
160 {
161 length = -1;
162 }
163
164 return Variant(string1.substr(position-1,length));
165}
166
167
168
169// This finds the first index of a substring within a string. It returns
170// 0 if the character is not found.
172{
173 //v[1] should have the parameter: a list of keys to wait for.
174 PList * plist = v.GetComplexData()->GetList();
175
176 PError::AssertType(plist->First(), PEAT_STRING, "Argument error in first parameter of function FindInString(<string>,<substring>,<pos>)]: ");
177 std::string str1 = plist->First();// plist->PopFront();
178
179
180 PError::AssertType(plist->Nth(2), PEAT_STRING, "Argument error in second parameter of function FindInString(<string>,<substring>,<pos>)]: ");
181 std::string str2 = plist->Nth(2); //plist->PopFront();
182
183 PError::AssertType(plist->Nth(3), PEAT_INTEGER, "Argument error in Third parameter of function FindInString(<string>,<substring>,<pos>)]: ");
184 int pos = plist->Nth(3); //plist->PopFront();
185
186
187 string::size_type newpos = str1.find(str2,pos-1);
188 if (newpos == string::npos)
189 return Variant(0);
190 else
191 return Variant((int)newpos+1);
192}
193
194
195
196
197// This splits the string by another string. If second string is "", it splits ever character.
199{
200 //v[1] should have the parameter: a list of keys to wait for.
201 PList * plist = v.GetComplexData()->GetList();
202
203 PError::AssertType(plist->First(), PEAT_STRING, "Argument error in first parameter of function SplitString(<string>,<substring>)]: ");
204 std::string str1 = plist->First();// plist->PopFront();
205
206
207 PError::AssertType(plist->Nth(2), PEAT_STRING, "Argument error in second parameter of function SplitString(<string>,<substring>)]: ");
208 std::string str2 = plist->Nth(2); //plist->PopFront();
209
210
211 std::string tmpstring = str1;
212 std::string sep = str2;
213 Variant ret = PEBLUtility::Tokenize(tmpstring.c_str(),*(sep.c_str()));
214
215 return ret;
216}
217
218
219
220
221
222// This copies text to the OS clipboard.
224{
225 //v[1] should have the parameter: a list of keys to wait for.
226 PList * plist = v.GetComplexData()->GetList();
227
228 PError::AssertType(plist->First(), PEAT_STRING, "Argument error in function CopyToClipboard(<string>)]: ");
229 std::string str1 = plist->First();// plist->PopFront();
230
231
233 return Variant(1);
234}
235
236
237// Detects the Unicode script of the text
238// Returns ISO 15924 4-letter code (e.g., "Arab", "Hebr", "Hani", "Thai")
239// Returns empty string for Latin/unknown scripts
241{
242 PList * plist = v.GetComplexData()->GetList();
243
244 PError::AssertType(plist->First(), PEAT_STRING, "Argument error in function DetectTextScript(<string>)]: ");
245 std::string text = plist->First();
246
247 std::string script = PEBLUtility::DetectScript(text);
248 return Variant(script);
249}
250
251
252// Determines if the text is right-to-left (RTL)
253// Can take either text string OR script code as input
255{
256 PList * plist = v.GetComplexData()->GetList();
257
258 PError::AssertType(plist->First(), PEAT_STRING, "Argument error in function IsRTL(<string>)]: ");
259 std::string input = plist->First();
260
261 // If input is a 4-letter script code, use it directly
262 // Otherwise, detect the script from the text
263 std::string script;
264 if (input.length() == 4 && std::isupper(input[0])) {
265 script = input;
266 } else {
267 script = PEBLUtility::DetectScript(input);
268 }
269
270 bool isRTL = PEBLUtility::IsRTLScript(script);
271 return Variant((int)isRTL);
272}
273
274
275// Gets appropriate font for text by detecting its script
276// Arguments: text, [fontType]
277// fontType: 0=sans (default), 1=mono, 2=serif
278// Returns font filename appropriate for the detected script
280{
281 PList * plist = v.GetComplexData()->GetList();
282
283 PError::AssertType(plist->First(), PEAT_STRING, "Argument error in first parameter of function GetFontForText(<text>, [fontType])]: ");
284 std::string text = plist->First();
285
286 // Optional font type parameter (default to 0 = sans-serif)
287 int fontType = 0;
288 if (plist->Length() >= 2) {
289 PError::AssertType(plist->Nth(2), PEAT_INTEGER, "Argument error in second parameter of function GetFontForText(<text>, [fontType])]: ");
290 fontType = plist->Nth(2);
291 if (fontType < 0 || fontType > 2) {
292 PError::SignalWarning("Font type must be 0 (sans), 1 (mono), or 2 (serif). Using 0.");
293 fontType = 0;
294 }
295 }
296
297 // Detect script from text
298 std::string script = PEBLUtility::DetectScript(text);
299
300 // If empty (Latin), use empty string; otherwise use the 4-letter code
301 std::string code = (script.empty()) ? "" : script;
302
303 // Get appropriate font
304 // If code is empty, GetFontForLanguageOrScript will return DejaVu (default Western)
305 std::string font = PEBLUtility::GetFontForLanguageOrScript(code.empty() ? "EN" : code, fontType);
306
307 return Variant(font);
308}
309
310
311// Gets the system locale from OS settings
312// Returns locale string like "ar", "en_US", "zh_CN", "he_IL"
313// Returns empty string if detection fails
315{
316 // No parameters needed - just query the OS via environment
317 std::string locale = myEnv->GetSystemLocale();
318 return Variant(locale);
319}
320
321
322// Determines if the system locale is RTL (Arabic, Hebrew)
323// Useful for setting default text box justification before any input
324// Returns 1 if RTL, 0 if LTR
326{
327 // No parameters needed - just query the OS via environment
328 bool isRTL = myEnv->IsSystemLocaleRTL();
329 return Variant((int)isRTL);
330}
331
332
333// RegexMatch(string, pattern) -> integer
334// Returns 1-based index of first match, or 0 if no match (consistent with FindInString)
336{
337 PList * plist = v.GetComplexData()->GetList();
338
340 "Argument error in first parameter of function RegexMatch(<string>, <pattern>)]: ");
341 std::string text = plist->First();
342
344 "Argument error in second parameter of function RegexMatch(<string>, <pattern>)]: ");
345 std::string pattern = plist->Nth(2);
346
347 int matchlen = 0;
348 int idx = re_match(pattern.c_str(), text.c_str(), &matchlen);
349
350 if (idx < 0)
351 return Variant(0); // No match
352 else
353 return Variant(idx + 1); // 1-based index (PEBL convention)
354}
355
PlatformEnvironment * myEnv
Definition PEBL.cpp:189
@ PEAT_INTEGER
Definition PError.h:44
@ PEAT_STRING
Definition PError.h:46
PList * GetList() const
Definition PList.h:45
Variant Nth(unsigned int n)
Definition PList.cpp:181
unsigned long Length() const
Definition PList.h:89
Variant First()
Definition PList.cpp:169
virtual std::string GetSystemLocale()
PComplexData * GetComplexData() const
Definition Variant.cpp:1299
Variant ToASCII(Variant v)
Variant SplitString(Variant v)
Variant Uppercase(Variant v)
Variant StringLength(Variant v)
Variant GetSystemLocale(Variant v)
Variant DetectTextScript(Variant v)
Variant Lowercase(Variant v)
Variant IsSystemLocaleRTL(Variant v)
Variant GetFontForText(Variant v)
Variant FindInString(Variant v)
Variant IsRTL(Variant v)
Variant CopyToClipboard(Variant v)
Variant RegexMatch(Variant v)
Variant SubString(Variant v)
std::string DetectScript(const std::string &text)
bool IsRTLScript(const std::string &script)
void CopyToClipboard(const std::string &text)
Variant Tokenize(const char *line, char separator)
std::string GetFontForLanguageOrScript(const std::string &code, int fontType)
void SignalWarning(const std::string &message)
Definition PError.cpp:119
void AssertType(Variant v, int type, const std::string &outsidemessage)
void SignalFatalError(const std::string &message)
int re_match(const char *pattern, const char *text, int *matchlength)