[英]How to trim following zeros from a string of scientific number in c++
I am trying to trim zeros from strings in scientific number form: 我正在尝试以科学数字形式从字符串中修剪零:
1.200e+12
should be 1.2e+12
1.200e+12
应该是1.2e+12
1.0200e+12
should be 1.02e+12
1.0200e+12
应该是1.02e+12
1.0000e+12
should be 1e+12
1.0000e+12
应该是1e+12
1.0e+12
should be 1e+12
1.0e+12
应该是1e+12
100e+12
should be 100e+12
100e+12
应该是100e+12
1.e+12
should be 1e+12
(optional) 1.e+12
应该是1e+12
(可选) I am using this function to do this: 我正在使用此功能来做到这一点:
std::regex_replace(s,std::regex("([^\\.]+(?=\\.)|[^\\.]+\\.\\d+?)0*(e.*)$"),\
"$1$2",std::regex_constants::format_first_only)
But the regex seems to be not correct. 但是正则表达式似乎是不正确的。 It gives me wrong result:
它给我错误的结果:
1.0e
for 1.000e
1.0e
为1.000e
1.0e
for 1.0e
1.0e
为1.0e
1.e
for 1.e
1.e
代表1.e
How can I do this with regex or is there another efficient way without using regex at all? 我该如何使用正则表达式来执行此操作,或者还有一种根本不用正则表达式的有效方法?
I would use a conditional regex like this: 我将使用这样的条件正则表达式:
(\d*)(?:(?=[.]0*e)[.]0*|(?![.]0+e)([.][0-9]*?)0*)(e(?:[+]\d+)?)
See regex demo . 参见regex演示 。 Replace with
$1$2$3
. 替换为
$1$2$3
。
The regex matches... 正则表达式匹配...
(\\d*)
- (Group 1) 0 or more digits (\\d*)
-(第1组)0或更多数字 (?:(?=[.]0*e)[.]0*|(?![.]0+e)([.][0-9]*?)0*)
- two alternatives: (?:(?=[.]0*e)[.]0*|(?![.]0+e)([.][0-9]*?)0*)
-两种选择:
(?=[.]0*e)[.]0*
- match 0 or more zeros if these are 0s coming after a dot up to e
(?=[.]0*e)[.]0*
-匹配0个或多个零(如果它们是0,则在点之后直到e
|
- or... (?![.]0+e)([.][0-9]*?)0*
- match and capture into Group 2 a dot with as few digits as possible before 0 or more 0
s if there are no just zeros after .
(?![.]0+e)([.][0-9]*?)0*
- 如果没有正则表达式, 则将第一个点匹配并捕获到第2组中,该点应在0或多个0
之前尽可能少之后为零.
up to e
e
(e(?:[+]\\d+)?)
- (Group 3) match and capture e
or e+
followed with 1 or more digits. (e(?:[+]\\d+)?)
-(第3组)匹配并捕获e
或e+
后跟1个或多个数字。 IDEONE demo : IDEONE演示 :
#include <iostream>
#include <regex>
using namespace std;
int main() {
std::vector<std::string> strings;
strings.push_back("1.200e+12");
strings.push_back("1.0200e+12");
strings.push_back("1.0000e+12");
strings.push_back("1.0e+12");
strings.push_back("1.e+12");
strings.push_back("100e");
strings.push_back("100e+12");
std::regex reg(R"((\d*)(?:(?=[.]0*e)[.]0*|(?![.]0+e)([.][0-9]*?)0*)(e(?:[+]\d+)?))");
for (size_t k = 0; k < strings.size(); k++)
{
std::cout << "Next string: " << strings[k] << std::endl;
std::cout << "Replace result: "
<< std::regex_replace(strings[k], reg, "$1$2$3") << std::endl;
}
return 0;
}
I'd suggest that you proceed with 2 steps: 我建议您进行2个步骤:
remove trailing 0
s: https://regex101.com/r/aV0sM6/1 删除尾随的
0
秒: https : //regex101.com/r/aV0sM6/1
RegEx: s/([0-9]+)\\.([0-9]*[^0])?(0*)[eE]([-+][0-9]+)/\\1.\\2e\\4/ Input: Output: 1.200e+12 1.2e+12 1.0200e+12 1.02e+12 1.0000e+12 1.e+12 1.0e+12 1.e+12 1.e+12 1.e+12
remove trailing .
删除尾随
.
s: https://regex101.com/r/zT3wI2/1 s: https : //regex101.com/r/zT3wI2/1
s/([0-9]+)\\.[eE]([-+][0-9]+)/\\1e\\2/ Input: Output: 1.2e+12 1.2e+12 1.02e+12 1.02e+12 1.e+12 1e+12 1.e+12 1e+12 1.e+12 1e+12
EDIT Here's another solution that doesn't use regular expressions: 编辑这是另一种不使用正则表达式的解决方案:
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
string trim(string str)
{
// return integers without modification
if (str.find('.') == string::npos)
{
return str;
}
// process floating point numbers
// find the exponent symbol
const size_t pos_e = str.rfind('e');
const size_t rpos_e = str.length() - pos_e;
// find the first trailing zero (if any)
const size_t rpos_firstTrailingZero = std::distance(
str.rbegin(),
std::find_if(str.rbegin() + rpos_e,
str.rend(),
[](const char c) { return c != '0'; })
);
const size_t pos_firstTrailingZero = str.length()
- rpos_firstTrailingZero;
// compute the trimming position
// if the fractional part was only zeros (e.g. 1.000), then trailing '.' should be removed
const size_t pos_trimming = (str[pos_firstTrailingZero - 1] != '.')
? pos_firstTrailingZero
: (pos_firstTrailingZero - 1);
// copy the exponent part to where the string should be trimmed
const size_t len_exp = str.length() - pos_e; // length of the exponentiation part
std::copy(str.begin() + pos_e,
str.end(),
str.begin() + pos_trimming);
str.resize(pos_trimming + len_exp);
// done
return str;
}
int main()
{
cout << trim("1.200e+12") << endl;
cout << trim("1.0200e+12") << endl;
cout << trim("1.0000e+12") << endl;
cout << trim("1.0e+12") << endl;
cout << trim("1.e+12") << endl;
cout << trim("100e") << endl;
cout << trim("100e+12") << endl;
}
Output: 输出:
1.2e+12
1.02e+12
1e+12
1e+12
1e+12
100e
100e+12
This is what I could think of, and it works for all your given cases. 这就是我能想到的,它适用于所有给定的情况。
string solve(string x)
{
string y;
auto d=x.find('.');
if (d==string::npos) return x;
for (int i=0; i!=d; i++) y.push_back(x[i]);
int j, k;
for (k=d+1; tolower(x[k])!='e'; k++);
for (j=k-1; x[j]=='0'; j--);
if (j==d) j--;
for (int i=d; i<=j; i++) y.push_back(x[i]);
for (int i=k; i<x.length(); i++) y.push_back(x[i]);
return y;
}
You could use a stack. 您可以使用堆栈。 For example:
例如:
The regex function is too heavy. 正则表达式功能太重。 It takes too much time comparing to a straight forward process.
与简单的过程相比,它花费了太多时间。 I ended up doing this without regex:
我最终没有使用正则表达式来执行此操作:
typedef std::string String;
bool stringContains(String s1,String s2){
if (s1.find(s2) != String::npos) {return true;}
else return false;}
String ltrim(String s,const String& delim){return s.erase(0,s.find_first_not_of(delim));}
String rtrim(String s,String delim){return s.erase(s.find_last_not_of(delim)+1);}
String trimZeroFromScientificNumber(const String& s){
if(!stringContains(s,"."))return s;
int pos = s.find_first_of("eE");
if(pos!=(int)String::npos){
return rtrim(rtrim(s.substr(0,pos),"0"),".")+s.substr(pos,1)+ltrim(s.substr(pos+1,String::npos),"0");
}
else return s;
}
Using this function it saved 0.2 seconds in 14 consecutive execution comparing to that regex function in a test run. 与测试运行中的regex函数相比,使用此函数可以在14次连续执行中节省0.2秒。
It can also easily be expanded to trim zeros from non-scientific numbers ( 1.00,1.00200 etc..). 还可以轻松地将其扩展为从非科学数字(1.00、1.00200等)中修剪零。
To get a function that can trim floating zeros from both scientific and non-scientific numbers, just change the else return s;
要获得一个可以从科学数和非科学数中修剪掉浮零的函数,只需更改
else return s;
(in the last line) to else return rtrim(rtrim(s,"0"),".");
(在最后一行),
else return rtrim(rtrim(s,"0"),".");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.