Arcane  v3.16.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
StringVariableReplace.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* StringVariableReplace.cc (C) 2000-2025 */
9/* */
10/* Classe permettant de remplacer les symboles d'une chaine de caractères */
11/* par une autre chaine de caractères définie dans les arguments de */
12/* lancement. */
13/* Un symbole est défini par une chaine de caractères entourée de @. */
14/* Exemple : @mon_symbole@ */
15/*---------------------------------------------------------------------------*/
16
17#include "arcane/core/internal/StringVariableReplace.h"
18
19#include "arcane/utils/CommandLineArguments.h"
20#include "arcane/utils/PlatformUtils.h"
21#include "arcane/utils/SmallArray.h"
22#include "arcane/utils/StringBuilder.h"
23#include "arcane/utils/String.h"
24#include "arcane/utils/FatalErrorException.h"
25#include "arcane/utils/List.h"
26
27/*---------------------------------------------------------------------------*/
28/*---------------------------------------------------------------------------*/
29
30namespace Arcane
31{
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
35
36String StringVariableReplace::
37replaceWithCmdLineArgs(StringView string_with_symbols, bool fatal_if_not_found, bool fatal_if_invalid)
38{
39 StringList args;
41 const CommandLineArguments cla{ args };
42 return replaceWithCmdLineArgs(cla.parameters(), string_with_symbols, fatal_if_not_found, fatal_if_invalid);
43}
44
96String StringVariableReplace::
97replaceWithCmdLineArgs(const ParameterList& parameter_list, StringView string_with_symbols, bool fatal_if_not_found, bool fatal_if_invalid)
98{
99 // Si la variable d'environnement ARCANE_REPLACE_SYMBOLS_IN_DATASET n'est pas
100 // définie, on ne touche pas à la chaine de caractères.
101 if (platform::getEnvironmentVariable("ARCANE_REPLACE_SYMBOLS_IN_DATASET").null() &&
102 parameter_list.getParameterOrNull("ARCANE_REPLACE_SYMBOLS_IN_DATASET").null()) {
103 return string_with_symbols;
104 }
105
106 if (string_with_symbols.empty())
107 return string_with_symbols;
108
109 Integer nb_at = 0;
110 Integer nb_at_with_escape = 0;
111
112 // Les arrobases peuvent être échappées. Il est nécessaire de les différencier pour avoir
113 // la taille du tableau des morceaux et pour vérifier la validité de la chaine de caractères.
114 _countChar(string_with_symbols, '@', nb_at, nb_at_with_escape);
115 if (nb_at == 0 && nb_at_with_escape == 0)
116 return string_with_symbols;
117
118 // Si le nombre d'arrobases est impaire, il y a forcément une incohérence.
119 if (fatal_if_invalid && nb_at % 2 == 1) {
120 ARCANE_FATAL("Invalid nb of @");
121 }
122
123 // Une arrobase sépare la chaine en deux morceaux. Donc le nombre de morceaux sera de "nb_at + 1".
124 // On ajoute les arrobases échappées. Ces arrobases sont considérées comme un symbole spécial et
125 // génèrent deux morceaux (donc "nb_at_with_escape * 2").
126 const Integer size_array_w_splits = (nb_at + 1) + (nb_at_with_escape * 2);
127
128 // Dans un cas valide, le nombre de morceaux doit être impaire.
129 // Dans le cas où l'utilisateur désactive le fatal_if_invalid et que le nombre de morceaux est paire,
130 // il ne faut pas qu'on considère le morceau final comme un symbole (voir la boucle plus bas pour comprendre).
131 const Integer max_index = size_array_w_splits % 2 == 0 ? size_array_w_splits - 1 : size_array_w_splits;
132
133 SmallArray<StringView> string_splited(size_array_w_splits);
134 _splitString(string_with_symbols, string_splited, '@');
135
136 StringBuilder combined{};
137
138 // Dans le tableau, les morceaux ayant une position impaire sont les élements entre arrobases
139 // et donc des symboles.
140 for (Integer i = 0; i < max_index; ++i) {
141 StringView part{ string_splited[i] };
142 if (part.empty())
143 continue;
144
145 // Les morceaux avec une position paire ne sont pas des symboles.
146 // On traite aussi le cas particulier des arrobases échappées.
147 if (i % 2 == 0 || part.bytes()[0] == '@') {
148 combined.append(part);
149 }
150 else {
151 String reference_input = parameter_list.getParameterOrNull(part);
152 if (reference_input.null()) {
153 if (fatal_if_not_found) {
154 ARCANE_FATAL("Symbol @{0}@ not found in the parameter list", part);
155 }
156 }
157 else {
158 combined.append(reference_input);
159 }
160 }
161 }
162
163 // Dans le cas où l'utilisateur désactive le fatal_if_invalid, le dernier morceau
164 // est à une position impaire mais n'est pas un symbole, donc on le rajoute ici.
165 if (size_array_w_splits % 2 == 0) {
166 combined.append(string_splited[string_splited.size() - 1]);
167 }
168
169 return combined.toString();
170}
171
172/*---------------------------------------------------------------------------*/
173/*---------------------------------------------------------------------------*/
174
191_splitString(StringView str_view, ArrayView<StringView> str_view_array, char c)
192{
193 /*
194 aa@aa -> "aa", "aa" 2 (fatal_if_invalid)
195 @aa@aa@aa@ -> "", "aa", "aa", "aa", "" 5
196 @aa@@aa@ -> "", "aa", "", "aa", "" 5
197 @ -> "", "" 2 (fatal_if_invalid)
198 @aa@ -> "", "aa", "" 3
199 @aa@aa\@aa -> "", "aa", "aa", "@", "aa" 5
200 @aa@\@@aa@ -> "", "aa", "", "@", "", "aa", "" 7
201 @aa@@aa@ -> "", "aa", "", "aa", "" 5
202 \@aa -> "", "@", "aa" 3
203 @aa@aa@aa -> "", "aa", "aa", "aa" 4 (fatal_if_invalid)
204 @aa@aa -> "", "aa", "aa" 3
205 */
206
207 Span<const Byte> str_span = str_view.bytes();
208
209 Int64 offset = 0;
210 Int64 len = str_view.length();
211 Integer index = 0;
212 bool previous_backslash = false;
213
214 for (Int64 i = 0; i < len; ++i) {
215 // Si on trouve une arrobase.
216 if (str_span[i] == c) {
217 // Si cette arrobase est précédée par un backslash.
218 if (previous_backslash) {
219 // On enregistre le morceau qu'on parcourait, sans le backslash.
220 str_view_array[index++] = str_view.subView(offset, i - 1 - offset);
221 // On rajoute l'arrobase.
222 str_view_array[index++] = str_view.subView(i, 1);
223
224 offset = i + 1;
225 previous_backslash = false;
226 }
227 else {
228 // On enregistre le morceau qu'on parcourait, sans l'arrobase.
229 str_view_array[index++] = str_view.subView(offset, i - offset);
230
231 offset = i + 1;
232 }
233 }
234 // Si on trouve un backslash.
235 else if (str_span[i] == '\\') {
236 // Et qu'on avait déjà trouvé un backslash, on n'y touche pas.
237 if (previous_backslash)
238 previous_backslash = false;
239 else
240 previous_backslash = true;
241 }
242 else {
243 previous_backslash = false;
244 }
245 }
246 // On ajoute le dernier morceau.
247 str_view_array[index] = str_view.subView(offset, len - offset);
248}
249
250/*---------------------------------------------------------------------------*/
251/*---------------------------------------------------------------------------*/
252
263_countChar(StringView str_view, char c, Integer& count_c, Integer& count_c_with_escape)
264{
265 count_c = 0;
266 count_c_with_escape = 0;
267 bool previous_backslash = false;
268
269 for (const Byte byte : str_view.bytes()) {
270 if (byte == c) {
271 if (previous_backslash) {
272 count_c_with_escape++;
273 previous_backslash = false;
274 }
275 else {
276 count_c++;
277 }
278 }
279 else if (byte == '\\') {
280 // On avait déjà trouvé un backslash, on n'y touche pas.
281 if (previous_backslash)
282 previous_backslash = false;
283 else
284 previous_backslash = true;
285 }
286 else {
287 previous_backslash = false;
288 }
289 }
290}
291
292/*---------------------------------------------------------------------------*/
293/*---------------------------------------------------------------------------*/
294
295} // namespace Arcane
296
297/*---------------------------------------------------------------------------*/
298/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Integer size() const
Nombre d'éléments du vecteur.
Vue modifiable d'un tableau d'un type T.
Liste de paramètres.
String getParameterOrNull(const String &param_name) const
Récupère le paramètre de nom param_name.
Tableau 1D de données avec buffer pré-alloué sur la pile.
Definition SmallArray.h:89
Vue d'un tableau d'éléments de type T.
Definition Span.h:513
Constructeur de chaîne de caractère unicode.
String toString() const
Retourne la chaîne de caractères construite.
static void _countChar(StringView str_view, char c, Integer &count_c, Integer &count_c_with_escape)
Méthode permettant de compter le nombre de caractères séparateurs dans une chaine de caractères.
static void _splitString(StringView str_view, ArrayView< StringView > str_view_array, char c)
Méthode permettant de splitter la chaine "str_view" en plusieurs morceaux. Les splits seront entre le...
Vue sur une chaîne de caractères UTF-8.
Definition StringView.h:47
constexpr Span< const Byte > bytes() const ARCCORE_NOEXCEPT
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition StringView.h:96
constexpr Int64 length() const ARCCORE_NOEXCEPT
Longueur en octet de la chaîne de caractères.
Definition StringView.h:99
StringView subView(Int64 pos) const
Sous-chaîne commençant à la position pos.
Definition StringView.cc:37
constexpr bool empty() const ARCCORE_NOEXCEPT
Vrai si la chaîne est nulle ou vide.
Definition StringView.h:105
Chaîne de caractères unicode.
bool null() const
Retourne true si la chaîne est nulle.
Definition String.cc:304
void fillCommandLineArguments(StringList &arg_list)
Remplit arg_list avec les arguments de la ligne de commande.
ARCCORE_BASE_EXPORT String getEnvironmentVariable(const String &name)
Variable d'environnement du nom name.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
List< String > StringList
Tableau de chaînes de caractères unicode.
Definition UtilsTypes.h:596
unsigned char Byte
Type d'un octet.
Definition BaseTypes.h:43