Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F91045899
string_algorithms.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Thu, Nov 7, 07:00
Size
12 KB
Mime Type
text/x-c++
Expires
Sat, Nov 9, 07:00 (2 d)
Engine
blob
Format
Raw Data
Handle
22158905
Attached To
rSPECMICP SpecMiCP / ReactMiCP
string_algorithms.cpp
View Options
/* =============================================================================
Copyright (c) 2014 - 2016
F. Georget <fabieng@princeton.edu> Princeton University
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
============================================================================= */
#include "string_algorithms.hpp"
#include <algorithm>
#define RANGE_SEP ':'
namespace
specmicp
{
namespace
utils
{
//! \brief Split a string
std
::
vector
<
std
::
string
>
split
(
const
std
::
string
&
to_split
,
char
separator
)
{
std
::
vector
<
std
::
string
>
splitted
;
auto
nb_elem
=
std
::
count
(
to_split
.
begin
(),
to_split
.
end
(),
separator
);
splitted
.
reserve
(
nb_elem
+
1
);
auto
start
=
to_split
.
begin
();
for
(
auto
current
=
to_split
.
cbegin
();
current
!=
to_split
.
cend
();
++
current
)
{
if
(
*
current
==
separator
)
{
splitted
.
emplace_back
(
to_split
.
substr
(
start
-
to_split
.
cbegin
(),
current
-
start
));
start
=
current
+
1
;
}
}
// last value
if
(
start
<
to_split
.
cend
())
{
splitted
.
emplace_back
(
to_split
.
substr
(
start
-
to_split
.
cbegin
()));
}
return
splitted
;
}
std
::
string
strip
(
const
std
::
string
&
to_trim
)
{
auto
start
=
to_trim
.
begin
();
auto
end
=
to_trim
.
end
();
// at the beginning
auto
current
=
to_trim
.
begin
();
for
(;
current
!=
to_trim
.
cend
();
++
current
)
{
if
(
*
current
!=
' '
)
{
start
=
current
;
break
;
}
}
if
(
current
==
to_trim
.
cend
())
{
return
""
;}
// empty string
// at the end
for
(
auto
current
=
to_trim
.
cend
()
-
1
;
current
>=
to_trim
.
begin
();
--
current
)
{
if
(
*
current
!=
' '
)
{
end
=
++
current
;
break
;
}
}
return
to_trim
.
substr
(
start
-
to_trim
.
begin
(),
end
-
start
);
}
void
parse_one_term
(
std
::
vector
<
index_t
>&
numbers
,
const
std
::
string
&
term
);
void
parse_one_term
(
std
::
vector
<
uindex_t
>&
numbers
,
const
std
::
string
&
term
);
template
<
typename
T
>
std
::
vector
<
T
>
range_indices_impl
(
const
std
::
string
&
range_str
)
{
std
::
vector
<
T
>
numbers
;
const
uindex_t
nb_sep
=
std
::
count
(
range_str
.
cbegin
(),
range_str
.
cend
(),
','
);
numbers
.
reserve
(
nb_sep
+
1
);
if
(
nb_sep
==
0
)
{
// if only one term
parse_one_term
(
numbers
,
range_str
);
}
else
{
const
std
::
vector
<
std
::
string
>
terms
=
split
(
range_str
,
','
);
for
(
const
auto
&
term:
terms
)
{
parse_one_term
(
numbers
,
term
);
}
}
// sort the indices
std
::
sort
(
numbers
.
begin
(),
numbers
.
end
());
return
numbers
;
}
template
<>
std
::
vector
<
index_t
>
range_indices
(
const
std
::
string
&
range_str
)
{
return
range_indices_impl
<
index_t
>
(
range_str
);
}
template
<>
std
::
vector
<
uindex_t
>
range_indices
(
const
std
::
string
&
range_str
)
{
return
range_indices_impl
<
uindex_t
>
(
range_str
);
}
void
parse_one_term
(
std
::
vector
<
index_t
>&
numbers
,
const
std
::
string
&
term
)
{
if
(
term
==
""
)
return
;
// check for empty terms
const
auto
to_anal
=
strip
(
term
);
const
auto
is_range
=
std
::
find
(
to_anal
.
cbegin
(),
to_anal
.
cend
(),
RANGE_SEP
);
if
(
is_range
==
to_anal
.
cend
())
{
// if just a number
numbers
.
push_back
(
std
::
stol
(
to_anal
));
}
else
{
// if a range
const
std
::
string
first_str
=
to_anal
.
substr
(
0
,
is_range
-
to_anal
.
cbegin
());
const
std
::
string
last_str
=
to_anal
.
substr
(
is_range
-
to_anal
.
cbegin
()
+
1
);
const
index_t
first
=
std
::
stol
(
first_str
);
const
index_t
last
=
std
::
stol
(
last_str
);
for
(
auto
ind
=
first
;
ind
<=
last
;
++
ind
)
{
numbers
.
push_back
(
ind
);
}
}
}
void
parse_one_term
(
std
::
vector
<
uindex_t
>&
numbers
,
const
std
::
string
&
term
)
{
if
(
term
==
""
)
return
;
// check for empty terms
const
auto
to_anal
=
strip
(
term
);
const
auto
is_range
=
std
::
find
(
to_anal
.
cbegin
(),
to_anal
.
cend
(),
RANGE_SEP
);
if
(
is_range
==
to_anal
.
cend
())
{
// if just a number
auto
val
=
std
::
stol
(
to_anal
);
if
(
val
<
0
)
{
throw
std
::
invalid_argument
(
"Negative argurment found in "
"positive ranges : '"
+
std
::
to_string
(
val
)
+
"'."
);
}
numbers
.
push_back
(
val
);
}
else
{
// if a range
const
std
::
string
first_str
=
to_anal
.
substr
(
0
,
is_range
-
to_anal
.
cbegin
());
const
std
::
string
last_str
=
to_anal
.
substr
(
is_range
-
to_anal
.
cbegin
()
+
1
);
const
index_t
first
=
std
::
stol
(
first_str
);
if
(
first
<
0
)
{
throw
std
::
invalid_argument
(
"Negative argurment found in "
"positive ranges : '"
+
std
::
to_string
(
first
)
+
"'."
);
}
const
index_t
last
=
std
::
stol
(
last_str
);
for
(
auto
ind
=
first
;
ind
<=
last
;
++
ind
)
{
numbers
.
push_back
(
ind
);
}
}
}
template
<
typename
T
>
class
ExpressionParser
{
public
:
ExpressionParser
(
const
std
::
string
&
expr
,
const
std
::
unordered_map
<
std
::
string
,
T
>&
vars
)
:
complete_expr
(
expr
),
variables
(
vars
)
{
}
T
parse
()
{
return
parse_term
(
complete_expr
);}
T
parse_value
(
const
std
::
string
&
value
);
T
parse_factor
(
const
std
::
string
&
factor
);
T
parse_term
(
const
std
::
string
&
term
);
private
:
const
std
::
string
&
complete_expr
;
const
std
::
unordered_map
<
std
::
string
,
T
>&
variables
;
};
template
<>
scalar_t
ExpressionParser
<
scalar_t
>::
parse_value
(
const
std
::
string
&
expr
)
{
auto
trimmed_expr
=
strip
(
expr
);
if
(
trimmed_expr
==
""
)
{
throw
std
::
invalid_argument
(
"Error while parsing : "
+
complete_expr
);
}
scalar_t
val
=
std
::
nan
(
""
);
try
{
std
::
size_t
pos
;
val
=
std
::
stod
(
trimmed_expr
,
&
pos
);
if
(
pos
!=
trimmed_expr
.
size
())
{
throw
std
::
logic_error
(
"Error while processing '"
+
expr
+
"'. Just a number was expected."
"Error occured while processing '"
+
complete_expr
+
"'."
);
}
}
catch
(
const
std
::
invalid_argument
&
e
)
{
auto
it
=
variables
.
find
(
trimmed_expr
);
if
(
it
==
variables
.
cend
())
{
throw
std
::
out_of_range
(
"Unknown variable '"
+
trimmed_expr
+
"' in parsing of '"
+
complete_expr
+
"'."
);
}
val
=
it
->
second
;
}
return
val
;
}
template
<>
index_t
ExpressionParser
<
index_t
>::
parse_value
(
const
std
::
string
&
expr
)
{
auto
trimmed_expr
=
strip
(
expr
);
index_t
val
=
INT_MAX
;
try
{
std
::
size_t
pos
;
val
=
std
::
stol
(
trimmed_expr
,
&
pos
);
if
(
pos
!=
trimmed_expr
.
size
())
{
throw
std
::
logic_error
(
"Error while processing"
+
expr
+
". Just a number was expected."
"Error occured while processing "
+
complete_expr
+
"."
);
}
}
catch
(
const
std
::
invalid_argument
&
e
)
{
auto
it
=
variables
.
find
(
trimmed_expr
);
if
(
it
==
variables
.
cend
())
{
throw
std
::
out_of_range
(
"Unknown variable '"
+
trimmed_expr
+
"' in parsing of '"
+
complete_expr
+
"'."
);
}
val
=
it
->
second
;
}
return
val
;
}
template
<
typename
T
>
T
ExpressionParser
<
T
>::
parse_factor
(
const
std
::
string
&
expr
)
{
auto
it
=
expr
.
find_last_of
(
"*/"
);
if
(
it
==
expr
.
npos
)
{
return
parse_value
(
expr
);
}
auto
val1
=
parse_factor
(
expr
.
substr
(
0
,
it
));
auto
val2
=
parse_value
(
expr
.
substr
(
it
+
1
));
if
(
expr
[
it
]
==
'*'
)
{
return
val1
*
val2
;
}
else
{
return
val1
/
val2
;
}
return
0
;
}
template
<
typename
T
>
T
ExpressionParser
<
T
>::
parse_term
(
const
std
::
string
&
expr
)
{
auto
it
=
expr
.
find_first_of
(
"+-"
);
if
(
it
==
expr
.
npos
)
{
return
parse_factor
(
expr
);
}
else
if
(
it
!=
0
)
{
auto
val1
=
parse_factor
(
expr
.
substr
(
0
,
it
));
auto
val2
=
parse_factor
(
expr
.
substr
(
it
+
1
));
if
(
expr
[
it
]
==
'+'
)
{
return
val1
+
val2
;
}
else
{
return
val1
-
val2
;
}
}
else
{
if
(
expr
[
it
]
==
'-'
)
{
return
-
parse_term
(
expr
.
substr
(
1
));
}
else
{
return
parse_term
(
expr
.
substr
(
1
));
}
}
return
0
;
}
template
<>
scalar_t
ExpressionParser
<
scalar_t
>::
parse_term
(
const
std
::
string
&
expr
)
{
auto
pred
=
[](
const
char
&
t
)
->
bool
{
return
((
t
==
'+'
)
or
(
t
==
'-'
));};
std
::
size_t
pos
=
0
;
char
op
;
auto
it
=
expr
.
begin
();
while
(
pos
<
expr
.
size
())
{
it
=
std
::
find_if
(
it
,
expr
.
end
(),
pred
);
if
(
it
==
expr
.
cend
())
{
pos
=
expr
.
size
();
break
;
}
op
=
*
it
;
pos
=
it
-
expr
.
cbegin
();
// xe-y notation => it's a number !
if
(
op
==
'-'
and
expr
[
pos
-
1
]
==
'e'
and
std
::
isdigit
(
expr
[
pos
-
2
]))
{
++
it
;
// jump to next char
continue
;
}
else
{
break
;
}
}
if
(
pos
==
expr
.
size
())
{
return
parse_factor
(
expr
);
}
if
(
pos
>
0
)
{
auto
val1
=
parse_factor
(
expr
.
substr
(
0
,
pos
));
auto
val2
=
parse_factor
(
expr
.
substr
(
pos
+
1
));
if
(
op
==
'+'
)
{
return
val1
+
val2
;
}
else
{
return
val1
-
val2
;
}
}
else
{
if
(
op
==
'-'
)
{
return
-
parse_term
(
expr
.
substr
(
1
));
}
else
{
return
parse_term
(
expr
.
substr
(
1
));
}
}
return
0
;
}
template
<>
scalar_t
parse_expression
(
const
std
::
string
&
expr
,
const
std
::
unordered_map
<
std
::
string
,
scalar_t
>&
variables
)
{
return
ExpressionParser
<
scalar_t
>
(
expr
,
variables
).
parse
();
}
template
<>
index_t
parse_expression
(
const
std
::
string
&
expr
,
const
std
::
unordered_map
<
std
::
string
,
index_t
>&
variables
)
{
return
ExpressionParser
<
index_t
>
(
expr
,
variables
).
parse
();
}
bool
string_to_bool
(
const
std
::
string
&
to_bool_str
)
{
// Contain the strings that matches true or false
static
const
char
*
true_str_test
[]
=
{
"True"
,
"true"
,
"1"
,
"yes"
,
"Yes"
,
"Y"
};
static
const
char
*
false_str_test
[]
=
{
"False"
,
"false"
,
"0"
,
"no"
,
"No"
,
"N"
};
auto
trimmed
=
strip
(
to_bool_str
);
bool
val
=
false
;
// test for true
for
(
auto
test:
true_str_test
)
{
if
(
test
==
trimmed
)
{
val
=
true
;
goto
exit
;
}
}
// test for false
for
(
auto
test:
false_str_test
)
{
if
(
test
==
trimmed
)
{
val
=
false
;
goto
exit
;
}
}
// no match => error
throw
std
::
invalid_argument
(
"Unrecognized value when converting to bool '"
+
trimmed
+
"'. Recognized value : true/false."
);
exit:
return
val
;
}
}
//end namespace utils
}
//end namespace specmicp
Event Timeline
Log In to Comment