环绕 std::getline()
Wrapping std::getline()
我正在努力解决以跨平台方式逐行读取文件输入的问题。
不同的平台使用不同的字符序列来表示新的 line/end 行。
std::getline
不会以跨平台的方式处理这些问题。
这是什么意思?
std::getline
根据编译可执行文件的平台更改其行为。在 Windows 平台上,它希望看到 CRLF
来表示行尾。在 Linux 上,它只需要 LF
。
- 它不处理文件包含非平台期望的行结尾的情况。例如,在 Windows 机器上创建的文件可能有
CRLF
行结尾。如果将该文件复制到 Linux 机器而不更改行结束格式,则 std::getline
“中断”。
在我看来,解决此问题的最简单方法是创建一个包装 std::getline
的新函数。像这样:
return_type GetLine(stream_type ifs, string_type s)
{
return_type ret = std::getline(ifs, s);
s.erase(std::remove(s.begin(), s.end(), '\r' ), s.end());
s.erase(std::remove(s.begin(), s.end(), '\n' ), s.end());
return ret;
}
然而在这一点上我卡住了。从一些搜索中,虽然 getline
returns 一个流对象(?)它也有一个隐式的转换为布尔运算符。
我可以强制 return_type
成为 bool
,但这会阻止我的包装函数返回流对象,如果将来需要这样的话。
我也无法充分理解 STL 模板,无法确定 stream_type
和 string_type
应该是什么。我可以强制它们成为 std::ifstream
和 std::string
,但我认为这个决定也会使函数不那么通用。
我应该如何进行这里操作?
您应该通过引用获取流,因为流通常无法复制。此外,字符串应该通过引用传递,因为你想写入它。
要通用,您可以使用与 std::getline
相同的界面。由于您要使用特定的定界符,因此不需要将它们作为参数传递。如果您将该函数设为模板,那么它将适用于也适用于 std::getline
:
的任何流
#include <iostream>
#include <sstream>
#include <string>
template< class CharT, class Traits, class Allocator >
std::basic_istream<CharT,Traits>& my_getline(
std::basic_istream<CharT,Traits>& input,
std::basic_string<CharT,Traits,Allocator>& str)
{
return std::getline(input,str);
}
int main() {
std::istringstream s{"hello world"};
std::string foo;
my_getline(s,foo);
std::cout << foo;
}
However at this point I'm stuck. From some searching, although getline returns a stream object (?) it also has an implicit cast-to-bool operator.
不是getline
转换为bool
,而是getline
返回的流可以转换为bool
。你的行几乎是正确的,但它需要是一个参考(并且你不需要明确地拼出类型):
auto& ret = std::getline(ifs, s);
// more code
return ret;
请注意,在遇到任何定界符之前我没有解决提取字符的实际问题(而不仅仅是您已经使用裸机 std::getline
获得的特定于平台的换行符)。
我正在努力解决以跨平台方式逐行读取文件输入的问题。
不同的平台使用不同的字符序列来表示新的 line/end 行。
std::getline
不会以跨平台的方式处理这些问题。
这是什么意思?
std::getline
根据编译可执行文件的平台更改其行为。在 Windows 平台上,它希望看到CRLF
来表示行尾。在 Linux 上,它只需要LF
。- 它不处理文件包含非平台期望的行结尾的情况。例如,在 Windows 机器上创建的文件可能有
CRLF
行结尾。如果将该文件复制到 Linux 机器而不更改行结束格式,则std::getline
“中断”。
在我看来,解决此问题的最简单方法是创建一个包装 std::getline
的新函数。像这样:
return_type GetLine(stream_type ifs, string_type s)
{
return_type ret = std::getline(ifs, s);
s.erase(std::remove(s.begin(), s.end(), '\r' ), s.end());
s.erase(std::remove(s.begin(), s.end(), '\n' ), s.end());
return ret;
}
然而在这一点上我卡住了。从一些搜索中,虽然 getline
returns 一个流对象(?)它也有一个隐式的转换为布尔运算符。
我可以强制 return_type
成为 bool
,但这会阻止我的包装函数返回流对象,如果将来需要这样的话。
我也无法充分理解 STL 模板,无法确定 stream_type
和 string_type
应该是什么。我可以强制它们成为 std::ifstream
和 std::string
,但我认为这个决定也会使函数不那么通用。
我应该如何进行这里操作?
您应该通过引用获取流,因为流通常无法复制。此外,字符串应该通过引用传递,因为你想写入它。
要通用,您可以使用与 std::getline
相同的界面。由于您要使用特定的定界符,因此不需要将它们作为参数传递。如果您将该函数设为模板,那么它将适用于也适用于 std::getline
:
#include <iostream>
#include <sstream>
#include <string>
template< class CharT, class Traits, class Allocator >
std::basic_istream<CharT,Traits>& my_getline(
std::basic_istream<CharT,Traits>& input,
std::basic_string<CharT,Traits,Allocator>& str)
{
return std::getline(input,str);
}
int main() {
std::istringstream s{"hello world"};
std::string foo;
my_getline(s,foo);
std::cout << foo;
}
However at this point I'm stuck. From some searching, although getline returns a stream object (?) it also has an implicit cast-to-bool operator.
不是getline
转换为bool
,而是getline
返回的流可以转换为bool
。你的行几乎是正确的,但它需要是一个参考(并且你不需要明确地拼出类型):
auto& ret = std::getline(ifs, s);
// more code
return ret;
请注意,在遇到任何定界符之前我没有解决提取字符的实际问题(而不仅仅是您已经使用裸机 std::getline
获得的特定于平台的换行符)。