I am trying to parse a file of locations with the following code however I am getting an odd regex_error and when I call the .what() function it simple gives "regex_error" with code 5, I can't seem to find the problem.
Code:
std::string line;
std::ifstream loc_file(argv[1]);
std::regex line_regex(R"(\S+)\s+([0-9\.]+) ([NS])\s+([0-9\.]+) ([EW])");
while (std::getline(loc_file, line)) {
std::smatch m;
std::regex_search(line, m, line_regex);
std::cout << "Location Matches:" << m.length() << std::endl;
std::cout << "Loc:" << m[1];
std::cout << " Lat:" << (m[3] == "S") ? -std::stod(m[2]) : std::stod(m[2]);
std::cout << " Lon:" << (m[5] == "W") ? -std::stod(m[4]) : std::stod(m[4]) << endl;
}
File Format:
Loc1 0.67408 N 23.47297 E
Loc2 3.01239 S 23.42157 W
OtherPlace 3.64530 S 17.47136 W
SecondPlace 26.13222 N 3.63386 E
I developed my regex on regex101.com you can test out my regex there
Also if it matters I am using VS2015
As it turns out it has to do with the fact that I am using an unescaped String Literal, which requires parentheses. The fixed code is here:
std::string line;
std::ifstream loc_file(argv[1]);
std::regex line_regex(R"((\S+)\s+([0-9\.]+) ([NS])\s+([0-9\.]+) ([EW]))");
while (std::getline(loc_file, line)) {
std::smatch m;
std::regex_search(line, m, line_regex);
std::cout << "Location Matches:" << m.length() << std::endl;
std::cout << "Loc:" << m[1];
std::cout << " Lat:" << (m[3] == "S") ? -std::stod(m[2]) : std::stod(m[2]);
std::cout << " Lon:" << (m[5] == "W") ? -std::stod(m[4]) : std::stod(m[4]) << endl;
}
Related
im new to Regex and C++.
My problem is, that '=' is matching when I search for [a-zA-Z]. But this is only a-z without '='?
Can anyone help me please?
string string1 = "s=s;";
enum states state = s1;
regex statement("[a-zA-Z]+[=][a-zA-Z0-9]+[;]");
regex rg_left_letter("[a-zA-Z]");
regex rg_equal("[=]");
regex rg_right_letter("[a-zA-Z0-9]");
regex rg_semicolon("[;]");
for (const auto &s : string1) {
cout << "Current Value: " << s << endl;
// step(&state, s);
if (regex_search(&s, rg_left_letter)) {
cout << "matching: " << s << endl;
} else {
cout << "not matching: " << s << endl;
}
// cout << "Step Executed with sate: " << state << endl;
}
This outputs:
Current Value: s
matching: s
Current Value: =
matching: =
Current Value: s
matching: s
Current Value: ;
not matching: ;
When you write
regex_search(&s, rg_left_letter)
you basically search the C-String &s for a match character-wise, beginning at the character s. Therefore, your loop will search for a match in the remaining sub-strings
s=s;
=s;
s;
;
Which will always succeed, except in the last case, as there is always one character in the entire string that fits your regex. Note however that this assumes that std::string has some 0-termination added, which is, as far as I can tell, not guaranteed if you do not explicitely use the c_str() method, making your code UB.
What you really want to use is the function regex_match, together with your original regex just as simple as:
#include <iostream>
#include <regex>
int main()
{
std::regex statement("[a-zA-Z]+[=][a-zA-Z0-9]+[;]");
if(std::regex_match("s=s;", statement)) { std::cout << "Hooray!\n"; }
}
This is working for me:
int main(void) {
string string1 = "s=s;";
enum states state = s1;
regex statement("[a-zA-Z]+[=][a-zA-Z0-9]+[;]");
regex rg_left_letter("[a-zA-Z]");
regex rg_equal("[=]");
regex rg_right_letter("[a-zA-Z0-9]");
regex rg_semicolon("[;]");
//for (const auto &s : string1) {
for (int i = 0; i < string1.size(); i++) {
cout << "Current Value: " << string1[i] << endl;
// step(&state, s);
if (regex_match(string1.substr(i, 1), rg_left_letter)) {
cout << "matching: " << string1[i] << endl;
} else {
cout << "not matching: " << string1[i] << endl;
}
// cout << "Step Executed with sate: " << state << endl;
}
cout << endl;
return 0;
}
So basically what I want to implement is that I have a text file and I have to find a specific word along with the location (location of line and where the word is on that line). how it could be implemented using basic knowledge of C++... I'm a newbie and haven't studies vector etc.Thanks for your help
fstream x;
x.open("file.txt);
while(getline(x,str)) {
//extract word from str and save in str1
if(reqWord == str1)
print("match found");
}`
This is kind of an advanced trick, but I suggest you try stringstream:
std::stringstream ss;
ss << str;
while(ss >> str1)
...
You can use find in order to search a specific occurrence of a search term. It will return the position of the first occurrence, otherwise npos if it's not on the current line.
Please find below a working example:
Edited - using regular expression with word boundary
#include <iostream>
#include <fstream>
#include <regex>
int main() {
std::cout << "Please input the file path" << std::endl;
std::string path;
std::cin >> path;
std::ifstream file(path.c_str());
if (file.is_open()) {
std::string search;
std::cout << "Please input the search term" << std::endl;
std::cin >> search;
std::regex rx("\\b" + search + "\\b");
int line_no = 1;
for (std::string line; std::getline(file, line); ++line_no) {
std::smatch m;
if (std::regex_search(line, m, rx)) {
std::cout << "match 1: " << m.str() << '\n';
std::cout << "Word " << search << " found at line: " << line_no << " position: " << m.position() + 1
<< std::endl;
break;
}
}
} else {
std::cerr << "File could not be opened." << std::endl;
return 1;
}
return 0;
}
I am trying to extract values from myString1 using std::stringstream like shown below:
// Example program
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
string myString1 = "+50years";
string myString2 = "+50years-4months+3weeks+5minutes";
stringstream ss (myString1);
char mathOperator;
int value;
string timeUnit;
ss >> mathOperator >> value >> timeUnit;
cout << "mathOperator: " << mathOperator << endl;
cout << "value: " << value << endl;
cout << "timeUnit: " << timeUnit << endl;
}
Output:
mathOperator: +
value: 50
timeUnit: years
In the output you can see me successfully extract the values I need, the math operator, the value and the time unit.
Is there a way to do the same with myString2? Perhaps in a loop? I can extract the math operator, the value, but the time unit simply extracts everything else, and I cannot think of a way to get around that. Much appreciated.
The problem is that timeUnit is a string, so >> will extract anything until the first space, which you haven't in your string.
Alternatives:
you could extract parts using getline(), which extracts strings until it finds a separator. Unfortunately, you don't have one potential separator, but 2 (+ and -).
you could opt for using regex directly on the string
you could finally split the strings using find_first_of() and substr().
As an illustration, here the example with regex:
regex rg("([\\+-][0-9]+[A-Za-z]+)", regex::extended);
smatch sm;
while (regex_search(myString2, sm, rg)) {
cout <<"Found:"<<sm[0]<<endl;
myString2 = sm.suffix().str();
//... process sstring sm[0]
}
Here a live demo applying your code to extract ALL the elements.
You could something more robust like <regex> like in the example below:
#include <iostream>
#include <regex>
#include <string>
int main () {
std::regex e ("(\\+|\\-)((\\d)+)(years|months|weeks|minutes|seconds)");
std::string str("+50years-4months+3weeks+5minutes");
std::sregex_iterator next(str.begin(), str.end(), e);
std::sregex_iterator end;
while (next != end) {
std::smatch match = *next;
std::cout << "Expression: " << match.str() << "\n";
std::cout << " mathOperator : " << match[1] << std::endl;
std::cout << " value : " << match[2] << std::endl;
std::cout << " timeUnit : " << match[4] << std::endl;
++next;
}
}
Output:
Expression: +50years
mathOperator : +
value : 50
timeUnit : years
Expression: -4months
mathOperator : -
value : 4
timeUnit : months
Expression: +3weeks
mathOperator : +
value : 3
timeUnit : weeks
Expression: +5minutes
mathOperator : +
value : 5
timeUnit : minutes
LIVE DEMO
I'd use getline for the timeUnit, but since getline can take only one delimiter, I'd search the string separately for mathOperator and use that:
string myString2 = "+50years-4months+3weeks+5minutes";
stringstream ss (myString2);
size_t pos=0;
ss >> mathOperator;
do
{
cout << "mathOperator: " << mathOperator << endl;
ss >> value;
cout << "value: " << value << endl;
pos = myString2.find_first_of("+-", pos+1);
mathOperator = myString2[pos];
getline(ss, timeUnit, mathOperator);
cout << "timeUnit: " << timeUnit << endl;
}
while(pos!=string::npos);
I feel like this is a pretty basic question but I did not find a post for it. If you know one please link it below.
So what I'm trying to do is look through a string and extract the numbers in groups of 2.
here is my code:
int main() {
string line = "P112233";
boost::regex e ("P([0-9]{2}[0-9]{2}[0-9]{2})");
boost::smatch match;
if (boost::regex_search(line, match, e))
{
boost::regex f("([0-9]{2})"); //finds 11
boost::smatch match2;
line = match[0];
if (boost::regex_search(line, match2, f))
{
float number1 = boost::lexical_cast<float>(match2[0]);
cout << number1 << endl; // this works and prints out 11.
}
boost::regex g(" "); // here I want it to find the 22
boost::smatch match3;
if (boost::regex_search(line, match3, g))
{
float number2 = boost::lexical_cast<float>(match3[0]);
cout << number2 << endl;
}
boost::regex h(" "); // here I want it to find the 33
boost::smatch match4;
if (boost::regex_search(line, match4, h))
{
float number3 = boost::lexical_cast<float>(match4[0]);
cout << number3 << endl;
}
}
else
cout << "found nothing"<< endl;
return 0;
}
I was able to get the first number but I have no idea how to get the second(22) and third(33).
what's the proper expression I need to use?
As #Cornstalks mentioned you need to use 3 capture groups and then you access them like that:
int main()
{
std::string line = "P112233";
boost::regex e("P([0-9]{2})([0-9]{2})([0-9]{2})");
boost::smatch match;
if (boost::regex_search(line, match, e))
{
std::cout << match[0] << std::endl; // prints the whole string
std::cout << match[1] << ", " << match[2] << ", " << match[3] << std::endl;
}
return 0;
}
Output:
P112233
11, 22, 33
I don't favour regular expressions for this kind of parsing. The key point being that the numbers are still strings when you're done with that hairy regex episode.
I'd use Boost Spirit here instead, which parses into the numbers all at once, and you don't even have to link to the Boost Regex library either, because Spirit is header-only.
Live On Coliru
#include <boost/spirit/include/qi.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
static qi::int_parser<int, 10, 2, 2> two_digits;
int main() {
std::string const s = "P112233";
std::vector<int> nums;
if (qi::parse(s.begin(), s.end(), "P" >> *two_digits, nums))
{
std::cout << "Parsed " << nums.size() << " pairs of digits:\n";
for(auto i : nums)
std::cout << " * " << i << "\n";
}
}
Parsed 3 pairs of digits:
* 11
* 22
* 33
Firstly here is my code I have so far:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int arraysize = 35;
int i = 0;
string line;
string searchTerm;
int main()
{
string words[arraysize];
ifstream wordFile;
wordFile.open ("wordFile.txt");
if (wordFile.is_open())
{
while (! wordFile.eof())
{
getline (wordFile, line);
words[i] = line;
i++;
}
wordFile.close();
}
else
{
cout << "Unable to open file" << endl;
}
for (int x = 0; x < arraysize; x++)
{
cout << words[x] << " ";
}
cout << "\n\nEnter in a word you would like to search in the story above:" << endl;
cin >> searchTerm;
for (int y = 0; y < arraysize; y++)
{
if (words[y].compare(searchTerm) !=0)
{
cout << "No match found" << endl;
}
}
}
What I have so far is the program reading from a textfile and then printing those words. What I wanna do next is let the user enter in a word that they would like to search in the textfile, if there is a word like the one they entered print that word if there isn't print out "There isn't a word like that in the textfile"
I just cant get the searching figured out, any suggestions on how to do this?
Here is an example of how you would search for strings within strings
// string::find
#include <iostream> // std::cout
#include <string> // std::string
int main ()
{
std::string str ("There are two needles in this haystack with needles.");
std::string str2 ("needle");
// different member versions of find in the same order as above:
std::size_t found = str.find(str2);
if (found!=std::string::npos)
std::cout << "first 'needle' found at: " << found << '\n';
found=str.find("needles are small",found+1,6);
if (found!=std::string::npos)
std::cout << "second 'needle' found at: " << found << '\n';
found=str.find("haystack");
if (found!=std::string::npos)
std::cout << "'haystack' also found at: " << found << '\n';
found=str.find('.');
if (found!=std::string::npos)
std::cout << "Period found at: " << found << '\n';
// let's replace the first needle:
str.replace(str.find(str2),str2.length(),"preposition");
std::cout << str << '\n';
return 0;
}
This should help you figure out exactly what you need to do
Notice how parameter pos is used to search for a second instance of the same search string. Output:
first 'needle' found at: 14
second 'needle' found at: 44
'haystack' also found at: 30
Period found at: 51
There are two prepositions in this haystack with needles.
How about:
int found = -1;
for (int y = 0; y < arraysize; y++)
{
if (words[y].compare(searchTerm) ==0)
{
found = y;
break;
}
}
if ( found != -1 )
cout << "found!" << endl;
else
cout << "No match found" << endl;
or shorter:
if ( std::find(std::begin(words), std::end(words), searchTerm) == std::end(words) )
cout << "not found";
else
cout << "found";