I maybe found a bug in std::regex_replace.
The following code should write "1a b2" with length 5, but it writes "1a2" with length 3.
Am I right? If not, why not?
#include <iostream>
#include <regex>
using namespace std;
int main()
{
string a = regex_replace("1<sn>2", std::regex("<sn>"), string("a\0b", 3));
cout << "a: " << a << "\n";
cout << a.length();
return 0;
}
This does seem to be a bug in libstdc++. Using a debugger I stepped into regex_replace, until getting to this part:
// std [28.11.4] Function template regex_replace
/**
* #brief Search for a regular expression within a range for multiple times,
and replace the matched parts through filling a format string.
* #param __out [OUT] The output iterator.
* #param __first [IN] The start of the string to search.
* #param __last [IN] One-past-the-end of the string to search.
* #param __e [IN] The regular expression to search for.
* #param __fmt [IN] The format string.
* #param __flags [IN] Search and replace policy flags.
*
* #returns __out
* #throws an exception of type regex_error.
*/
template<typename _Out_iter, typename _Bi_iter,
typename _Rx_traits, typename _Ch_type,
typename _St, typename _Sa>
inline _Out_iter
regex_replace(_Out_iter __out, _Bi_iter __first, _Bi_iter __last,
const basic_regex<_Ch_type, _Rx_traits>& __e,
const basic_string<_Ch_type, _St, _Sa>& __fmt,
regex_constants::match_flag_type __flags
= regex_constants::match_default)
{
return regex_replace(__out, __first, __last, __e, __fmt.c_str(), __flags);
}
Referencing this write-up at cppreference.com, this seems to be implementing the first overload, the one that takes a std::string for the replacement string, by calling its c_str() and then calling the 2nd overload, the one that takes a const char * parameter, for the actual implementation. And that explains the observed behavior. I can't find anything that requires this approach.
Stepping further into the actual implementation:
auto __len = char_traits<_Ch_type>::length(__fmt);
__out = __i->format(__out, __fmt, __fmt + __len, __flags);
So, it determines the length of the replacement string and passes the replacement string, as a beginning and an ending iterator, into format().
This seems like it should be the other way around, with __fmt preserved as a std::basic_string, and passing iterators directly derived from it into format().
Related
How to avoid matching unwanted blocks in regex.
For example, I just want to match the static prototypes in C language and how to make it not include the main function.
/**
* #brief
*
* #param dsc
*/
static void func1(const char *dsc);
/**
* #brief
*
* #param argc
* #param argv
* #return int
*/
int main(int argc, char *argv[]);
/**
* #brief
*
* #param dsc
*/
static void fun2(const char *dsc);
my regex is
\/\*[\w\W]*?\*\/\n+^static.*\);
and it alway match the main function prototypes. In Vscode just like this:
You can use
/\*(?:(?!/\*|\*/)[\w\W])*?\*/\n+static.*\);
Note that you do not need to escape the / char in the search and replace field since the regex is defined with a mere string, not a regex literal notation where / chars are used as regex delimiters.
The (?:(?!/\*|\*/)[\w\W])*? part makes it match any char, zero or more but as few as possible times, that does not start a /* or */ char sequence.
You do not need ^ as a start of a line anchor here since it makes no sense after \n+, it is implied there.
Good morning,
I'm implementing this class in C++ but it gives some problem with OCTET_STRING type. In fact, removing those variables it works but obviously I need them too.
class MIXIM_API BSMblob : public cObject
{
public:
long MsgCount;
OCTET_STRING TemporaryID;
long DSecond;
long Latitude;
long Longitude;
OCTET_STRING Elevation;
OCTET_STRING PositionalAccuracy;
OCTET_STRING TransmissionAndSpeed;
long Heading;
OCTET_STRING SteeringWheelAngle;
OCTET_STRING AccelerationSet4Way;
OCTET_STRING BrakeSystemStatus;
/*other line of codes */
/** #brief Returns a string with the value of the BSMblobinate. */
std::string info() const;
};
inline std::ostream& operator<<(std::ostream& os, const BSMblob& BSMblob)
{
return os << "(" << BSMblob.MsgCount << "," << BSMblob.TemporaryID
<< "," << BSMblob.DSecond << "," << BSMblob.Latitude
<< "," << BSMblob.Longitude << "," << BSMblob.Elevation
<< "," << BSMblob.PositionalAccuracy << "," << BSMblob.TransmissionAndSpeed
<< "," << BSMblob.Heading << "," << BSMblob.SteeringWheelAngle
<< "," << BSMblob.AccelerationSet4Way << "," << BSMblob.BrakeSystemStatus
<< ")";
}
The error is => error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream’ and ‘const OCTET_STRING’)
P.S. I was also wondering if it is possible to cast a double variable to a OCTET_STRING.
Thank you everybody
Here the OCTET_STRING.h :
#ifndef _OCTET_STRING_H_
#define _OCTET_STRING_H_
#include <asn_application.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct OCTET_STRING {
uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */
int size; /* Size of the buffer */
asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */
} OCTET_STRING_t;
extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING;
asn_struct_free_f OCTET_STRING_free;
asn_struct_print_f OCTET_STRING_print;
asn_struct_print_f OCTET_STRING_print_utf8;
ber_type_decoder_f OCTET_STRING_decode_ber;
der_type_encoder_f OCTET_STRING_encode_der;
xer_type_decoder_f OCTET_STRING_decode_xer_hex; /* Hexadecimal */
xer_type_decoder_f OCTET_STRING_decode_xer_binary; /* 01010111010 */
xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */
xer_type_encoder_f OCTET_STRING_encode_xer;
xer_type_encoder_f OCTET_STRING_encode_xer_utf8;
per_type_decoder_f OCTET_STRING_decode_uper;
per_type_encoder_f OCTET_STRING_encode_uper;
/******************************
* Handy conversion routines. *
******************************/
/*
* This function clears the previous value of the OCTET STRING (if any)
* and then allocates a new memory with the specified content (str/size).
* If size = -1, the size of the original string will be determined
* using strlen(str).
* If str equals to NULL, the function will silently clear the
* current contents of the OCTET STRING.
* Returns 0 if it was possible to perform operation, -1 otherwise.
*/
int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size);
/* Handy conversion from the C string into the OCTET STRING. */
#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1)
/*
* Allocate and fill the new OCTET STRING and return a pointer to the newly
* allocated object. NULL is permitted in str: the function will just allocate
* empty OCTET STRING.
*/
OCTET_STRING_t *OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td,
const char *str, int size);
/****************************
* Internally useful stuff. *
****************************/
typedef struct asn_OCTET_STRING_specifics_s {
/*
* Target structure description.
*/
int struct_size; /* Size of the structure */
int ctx_offset; /* Offset of the asn_struct_ctx_t member */
enum asn_OS_Subvariant {
ASN_OSUBV_ANY, /* The open type (ANY) */
ASN_OSUBV_BIT, /* BIT STRING */
ASN_OSUBV_STR, /* String types, not {BMP,Universal}String */
ASN_OSUBV_U16, /* 16-bit character (BMPString) */
ASN_OSUBV_U32 /* 32-bit character (UniversalString) */
} subvariant;
} asn_OCTET_STRING_specifics_t;
#ifdef __cplusplus
}
#endif
#endif /* _OCTET_STRING_H_ */
The error message from the compiler is quite clear and unambiguous: there is no
std::ostream& operator<<(std::ostream&, OCTET_STRING const&);
that it can use. If OCTET_STRING was a sensibly defined C++ type, then said operator would have been implemented. The fact that it's missing either means that OCTET_STRINGs should never be used in I/O, that the class has been provided by somebody not very much versed in the art of programming, or that it's a piece of C code that you're abusing.
To remedy, either abandon the use of OCTET_STRING (best) or provide a definition for said operator (ideally inline) yourself.
Note that OCTET_STRING is not a standard C++ type. It appears to be some C struct and a Windows thing. Using it obviously causes problems, but also will render your code non-portable. I can only highly recommend to avoid using OCTET_STRING. W/o much knowledge of what a OCTET_STRING does, I cannot say what to replace it with, but perhaps you know what you're using it for? I.e. what is the real type of Elevation in your code? It seems that double does the job for most if not all of them.
Just write one:
std::ostream& operator<<(std::ostream& os, const OCTET_STRING& whatever)
{
// print to os
return os;
}
This code compiles and runs fine as expected on Ideone:
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::wstring> strVec;
strVec.insert(strVec.end(), { L"black", L"white", L"red" });
strVec.insert(strVec.end(), { L"blue", L"green" }); // STL exception
for (auto &i : strVec) {
std::wcout << i << " ";
}
return 0;
}
However, fails with "invalid iterator range" in MSVC (Visual Studio 2013).. Any insight?
BTW, inserting more elements works, e.g. on the second insert, this works in MSVC:
strVec.insert( strVec.end(), { L"blue", L"green", L"yellow" } );
Related to capacity/size and invalidating some iterators? But second insert requests new iterator end(), which must be valid, right? Or... it's actually about initializer list?
Note: Not looking for workarounds here (tons of them) - just trying to figure out whether this is MSVC-specific bug or something legit wrong is going on...
VS 2013 has selected the overload vector<T>::insert(const_iterator, const T&), constructing wstring from a pair of pointers const wchar*, const wchar* interpreted as the start and end of a range of characters; note that a wide string literal decays to a const wchar* pointer. This is why the problem only occurs when you try to insert precisely 2 elements.
Here's the call stack:
msvcp120d.dll!std::_Debug_message(const wchar_t * message, const wchar_t * file, unsigned int line) Line 15 C++
Project1.exe!std::_Debug_range2<wchar_t const *>(const wchar_t * _First, const wchar_t * _Last, const wchar_t * _File, unsigned int _Line, std::random_access_iterator_tag __formal) Line 576 C++
Project1.exe!std::_Debug_range<wchar_t const *>(const wchar_t * _First, const wchar_t * _Last, const wchar_t * _File, unsigned int _Line) Line 584 C++
Project1.exe!std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >(const wchar_t * _First, const wchar_t * _Last) Line 860 C++
Project1.exe!main() Line 9 C++
VS 2013 is erroneous, because [over.ics.rank]:
3 - [...]
List-initialization sequence L1 is a better conversion sequence than list-initialization sequence L2 if:
L1 converts to std::initializer_list<X> for some X and L2 does not [...]
This is fixed in VS2015.
Possibly this happens because when you write { L"blue", L"green" } compiler use them as two pointers to construct value (std::wstring) and pass it into next std::vector::insert overloading:
insert( const_iterator pos, const T& value );
So it's likely that running from pointer L"blue" to L"green" ends somewhere where program has no permission to read, or it's check that first pointer is less than second and throw exception when they not.
Given an old-style const char * pointer and a length, is there a way to call std::regex_search() on it without first copying the contents of the buffer into a std::string? Here is a simple example of the problem I have:
#include <regex>
int main()
{
const char *text = "123 foobar 456";
const size_t len = strlen(text);
const std::regex rx(" (.+)bar");
std::smatch what;
std::regex_search( text, text+len, what, rx); // <- problematic line
return 0;
}
I thought the 5th std::regex_search() that takes two iterators is what I need, but I'm not fully understanding how to convert pointers to iterators. When I try to compile the code above, I get this:
g++ -std=c++11 test.cpp
test.cpp:11:45: error: no matching function for call to ‘regex_search(const char*&, const char*, std::smatch&, const regex&)’
/usr/include/c++/4.9/bits/regex.h:2131:5: note: template<class _Bi_iter, class _Alloc, class _Ch_type, class _Rx_traits> bool std::regex_search(_Bi_iter, _Bi_iter, std::match_results<_BiIter, _Alloc>&, const std::basic_regex<_CharT, _TraitsT>&, std::regex_constants::match_flag_type)
regex_search(_Bi_iter __s, _Bi_iter __e,
...and a lot more errors!
Can const char * be converted to the necessary iterator? Did I do it wrong? Am I misunderstanding how this works?
The error in your code is that you're using the wrong match_results type. smatch is supposed to be used when you have an std::string object and you're passing std::string::iterators to the regex function. When you have raw char const *s use cmatch instead.
Change
std::smatch what;
to
std::cmatch what;
Live demo
This is my first time making a hash table. I'm trying to associate strings (the keys) with pointers to objects (the data) of class Strain.
// Simulation.h
#include <ext/hash_map>
using namespace __gnu_cxx;
struct eqstr
{
bool operator()(const char * s1, const char * s2) const
{
return strcmp(s1, s2) == 0;
}
};
...
hash_map< const char *, Strain *, hash< const char * >, struct eqstr > liveStrainTable;
In the Simulation.cpp file, I attempt to initialize the table:
string MRCA;
for ( int b = 0; b < SEQ_LENGTH; b++ ) {
int randBase = rgen.uniform(0,NUM_BASES);
MRCA.push_back( BASES[ randBase ] );
}
Strain * firstStrainPtr;
firstStrainPtr = new Strain( idCtr, MRCA, NUM_STEPS );
liveStrainTable[ MRCA ]= firstStrainPtr;
I get an error message that reads "no match for ‘operator[]’ in ‘((Simulation*)this)->Simulation::liveStrainTable[MRCA]’." I've also tried using "liveStrainTable.insert(...)" in different ways, to no avail.
Would really love some help on this. I'm having a difficult time understanding the syntax appropriate for SGI hash_map, and the SGI reference barely clarifies anything for me. Thanks.
Try liveStrainTable[ MRCA.c_str() ]= firstStrainPtr;. It expects const char * as type of key value, but MRCA has type string.
Another way is to change liveStrainTable to:
hash_map< string, Strain *, hash<string>, eqstr > liveStrainTable;
Others answered your direct question, but may I suggest using unordered_map instead - it's coming with the next version of the STL and is supported by all major compilers.
hash_map is not part of STL. There's no implementation provided for hash, or in other words, the hash_map can't hash strings by default. You need your own hash function. T
Try:
typedef struct {
size_t operator()( const string& str ) const {
return __gnu_cxx::__stl_hash_string( str.c_str() );
}
} strhash;
hash_map< string, Strain *, strhash, eqstr > liveStrainTable;
The hash_map is defined with const char * as the key type and you are using an std::string as the key when accessing. These are 2 different types, the template did not build an operator for the second type, so this is an error. Use std::string for the hashmap definition or use MRCA.c_str()
Right now, you have a type mis-match. You're passing MRCA (a string) where a char const * is expected. You can either use c_str() to get a char const * from the string, or (far better) change the definition of your hash table to take a string as its key type.