C 以可移植和国际友好的方式删除换行符
C Removing Newlines in a Portable and International Friendly Way
这里的简单问题和一个可能很棘手的答案:我正在寻找一种便携和本地化友好的方法来删除 C 中的尾随换行符,最好是基于标准的东西。
我已经知道以下解决方案:
正在解析 \r
和 \n
的某种组合。在处理 Windows、*nix 和 Mac 时真的不太好,它们都使用不同的序列来表示新行。另外,其他语言甚至对新行使用相同的转义序列吗?我希望这会在使用与英语不同字形的语言中爆炸(比如日语等)。
删除尾随 n
字节并替换最后的 [=13=]
。似乎是一种更脆弱的方式来执行上述操作。
isspace
看起来很诱人,但我只需要匹配换行符。其他空格被认为是有效的标记文本。
C++ 有一个 class 可以做到这一点,但在纯 C 世界中它对我帮助不大。
locale.h
似乎是我所追求的,但我看不到任何与提取换行符相关的内容。
因此,这是我必须 "roll my own" 功能的一个实例,还是我遗漏了什么?谢谢!
解决方案
我最终结合了 Weather Vane
和 Loic
的两个答案,作为我的最终解决方案。有用的是使用方便的 strcspn
函数在 Loic 提供的链接中 selected 的第一个换行符处中断。因此,我可以 select 基于许多支持的语言环境的定界符。很好的一点是,在这个级别上有太多的一般支持;我什至不知道西里尔字母有几种相互竞争的编码。
这样我就可以在使用标准库函数的同时实现"good enough"多国支持
由于我只能接受一个答案,所以我 selecting 了 Weather Vane,因为他是我使用的最后一个调用。话虽如此,这两个答案确实对我有用。
我知道的最好的是
buffer [ strcspn(buffer, "\r\n") ] = 0;
这是处理 \r
和 \n
的所有组合的安全方法 - 两者,一个或 none.
我建议用一个标准 space (US-ASCII 0x20) 替换一个或多个白色 space 字符。仅考虑 ISO-8859-1 字符(https://en.wikipedia.org/wiki/ISO/IEC_8859-1),whitespace 由 0x00..0x20(C0 控制字符和 space)和 0x7F..0xA0(删除, C1 控制字符和不间断 space)。请注意,US-ASCII 是 ISO-8859-1 的子集。
但要考虑到 Windows1251 (https://en.wikipedia.org/wiki/Windows-1251) 将不同的可见(非控制)字符分配给范围 0x80..0x9F。在这种情况下,这些字节无法在不丢失文本信息的情况下被 spaces 替换。
有关白色 space 字符的广泛定义的资源:
- https://en.wikipedia.org/wiki/Unicode_character_property#Whitespace
- http://unicode.org/reports/tr23/
- http://www.unicode.org/Public/8.0.0/charts/CodeCharts.pdf
还要考虑到可能会使用不同的编码,最常见的是:
- ISO-8859-1 (https://en.wikipedia.org/wiki/ISO/IEC_8859-1)
- UTF-8 (https://en.wikipedia.org/wiki/UTF-8)
- Windows1251 (https://en.wikipedia.org/wiki/Windows-1251)
但在非西方国家(例如俄罗斯、日本),进一步的字符编码也很常见。存在许多编码,但尝试支持每一种已知编码可能没有意义。
因此尝试定义和限制您的用例,因为完全通用地实现它意味着大量工作。
此答案适用于遇到相同问题的 C++ 用户。
可以像这样为任何语言环境和字符类型匹配换行符:
#include <locale>
template<class Char>
bool is_newline(Char c, std::locale const & loc = std::locale())
{
// Translate character into default locale and character type.
// Then, test against '\n', which is the only newline character there.
return std::use_facet< std::ctype<Char>>(loc).narrow(c, ' ') == '\n';
}
现在,可以像这样删除所有尾随换行符:
void remove_trailing_newlines(std::string & str) {
while (!str.empty() && is_newline(*str.rbegin())
str.pop_back();
}
这应该是绝对可移植的,因为它只依赖于标准 C++ 函数。
这里的简单问题和一个可能很棘手的答案:我正在寻找一种便携和本地化友好的方法来删除 C 中的尾随换行符,最好是基于标准的东西。
我已经知道以下解决方案:
正在解析
\r
和\n
的某种组合。在处理 Windows、*nix 和 Mac 时真的不太好,它们都使用不同的序列来表示新行。另外,其他语言甚至对新行使用相同的转义序列吗?我希望这会在使用与英语不同字形的语言中爆炸(比如日语等)。删除尾随
n
字节并替换最后的[=13=]
。似乎是一种更脆弱的方式来执行上述操作。isspace
看起来很诱人,但我只需要匹配换行符。其他空格被认为是有效的标记文本。C++ 有一个 class 可以做到这一点,但在纯 C 世界中它对我帮助不大。
locale.h
似乎是我所追求的,但我看不到任何与提取换行符相关的内容。
因此,这是我必须 "roll my own" 功能的一个实例,还是我遗漏了什么?谢谢!
解决方案
我最终结合了 Weather Vane
和 Loic
的两个答案,作为我的最终解决方案。有用的是使用方便的 strcspn
函数在 Loic 提供的链接中 selected 的第一个换行符处中断。因此,我可以 select 基于许多支持的语言环境的定界符。很好的一点是,在这个级别上有太多的一般支持;我什至不知道西里尔字母有几种相互竞争的编码。
这样我就可以在使用标准库函数的同时实现"good enough"多国支持
由于我只能接受一个答案,所以我 selecting 了 Weather Vane,因为他是我使用的最后一个调用。话虽如此,这两个答案确实对我有用。
我知道的最好的是
buffer [ strcspn(buffer, "\r\n") ] = 0;
这是处理 \r
和 \n
的所有组合的安全方法 - 两者,一个或 none.
我建议用一个标准 space (US-ASCII 0x20) 替换一个或多个白色 space 字符。仅考虑 ISO-8859-1 字符(https://en.wikipedia.org/wiki/ISO/IEC_8859-1),whitespace 由 0x00..0x20(C0 控制字符和 space)和 0x7F..0xA0(删除, C1 控制字符和不间断 space)。请注意,US-ASCII 是 ISO-8859-1 的子集。
但要考虑到 Windows1251 (https://en.wikipedia.org/wiki/Windows-1251) 将不同的可见(非控制)字符分配给范围 0x80..0x9F。在这种情况下,这些字节无法在不丢失文本信息的情况下被 spaces 替换。
有关白色 space 字符的广泛定义的资源:
- https://en.wikipedia.org/wiki/Unicode_character_property#Whitespace
- http://unicode.org/reports/tr23/
- http://www.unicode.org/Public/8.0.0/charts/CodeCharts.pdf
还要考虑到可能会使用不同的编码,最常见的是:
- ISO-8859-1 (https://en.wikipedia.org/wiki/ISO/IEC_8859-1)
- UTF-8 (https://en.wikipedia.org/wiki/UTF-8)
- Windows1251 (https://en.wikipedia.org/wiki/Windows-1251)
但在非西方国家(例如俄罗斯、日本),进一步的字符编码也很常见。存在许多编码,但尝试支持每一种已知编码可能没有意义。
因此尝试定义和限制您的用例,因为完全通用地实现它意味着大量工作。
此答案适用于遇到相同问题的 C++ 用户。
可以像这样为任何语言环境和字符类型匹配换行符:
#include <locale>
template<class Char>
bool is_newline(Char c, std::locale const & loc = std::locale())
{
// Translate character into default locale and character type.
// Then, test against '\n', which is the only newline character there.
return std::use_facet< std::ctype<Char>>(loc).narrow(c, ' ') == '\n';
}
现在,可以像这样删除所有尾随换行符:
void remove_trailing_newlines(std::string & str) {
while (!str.empty() && is_newline(*str.rbegin())
str.pop_back();
}
这应该是绝对可移植的,因为它只依赖于标准 C++ 函数。