【问题标题】:D: how to remove last char in string?D:如何删除字符串中的最后一个字符?
【发布时间】:2015-04-02 12:40:37
【问题描述】:

在我的例子中,我需要删除字符串中的最后一个字符,它是逗号 (","):

foreach(line; fcontent.splitLines)
{
    string row = line.split.map!(a=>format("'%s', ", a)).join;
    writeln(row.chop.chop);
}

我只找到了一种方法 - 调用两次 Chop。首先删除\r\n,然后删除最后一个字符。

有没有更好的办法?

【问题讨论】:

  • var newString = string

标签: string d


【解决方案1】:
import std.array;
if (!row.empty)
    row.popBack();

【讨论】:

  • 这是正确答案。奇怪的是其他解决方案有多么复杂。
  • 次要问题是 OP 的情况需要两次调用 popBack() ,每次都首先检查 row.empty() 是否正确。这假设他的输入以 \r\n 终止,似乎是这种情况。
  • 您可以在不保留终止符的情况下拆分字符串。 foreach(line, content.splitLines(keepTerminator.no)) { ... }
【解决方案2】:

字符串处理通常会发生这种情况,这取决于您对 Unicode 的关注程度。

如果您只使用 ASCII,那非常简单:

import std.encoding;
// no "nice" ASCII literals, D really encourages Unicode
auto str1 = cast(AsciiString) "abcde";
str1 = str1[0 .. $-1]; // get slice of everything but last byte
auto str2 = cast(AsciiString) "abcde\n\r";
str2 = str2[0 .. $-3]; // same principle

在“最后一个字符”中,实际上意味着 unicode 代码点 (http://unicode.org/glossary/#code_point),它变得有点复杂。简单的方法就是只依赖D自动解码和算法:

import std.range, std.stdio;
auto range = "кириллица".retro.drop(1).retro();
writeln(range);

这里的retro (http://dlang.org/phobos/std_range.html#.retro) 是一个惰性反向迭代函数。它接受任何范围(unicode 字符串是有效范围)并返回能够向后迭代它的包装器。

drop (http://dlang.org/phobos/std_range.html#.drop) 只是弹出一个范围元素并忽略它。再次调用 retro 会将迭代顺序恢复正常,但现在删除了最后一个元素。

它与 ASCII 版本不同的原因在于 Unicode(特别是 D 默认为 UTF-8)的性质——它不允许随机访问任何代码点。您实际上需要将它们一一解码以获得任何所需的索引。幸运的是,D 负责所有解码,您将其隐藏在方便的范围接口后面。

对于那些想要更多 Unicode 正确性的人来说,应该可以对字素进行操作 (http://unicode.org/glossary/#grapheme):

import std.range, std.uni, std.stdio;
auto range = "abcde".byGrapheme.retro.drop(1).retro();
writeln(range);

很遗憾,由于 Phobos 中的错误,目前似乎不支持这种特定模式。我创建了一个关于它的问题:https://issues.dlang.org/show_bug.cgi?id=14394

【讨论】:

  • 如果它只是一个逗号,你可以很容易地检查字节并这样做,节省了大量的unicode表和处理麻烦......
  • 是的,我什至不确定 DMD 是否会正确优化所有范围实用程序以直接访问最后一个字节 - 但仍然不想建议在一般情况下不适合的解决方案 ;)
【解决方案3】:

注意:将我的答案更新为更简洁,并删除了 'map!' 中的 lambda 函数因为它有点丑。

import std.algorithm, std.stdio;
import std.string;
void main(){
    string fcontent = "I am a test\nFile\nwith some,\nCommas here and\nthere,\n";
    auto data = fcontent
        .splitLines
        .map!(a => a.replaceLast(","))
        .join("\n");
    writefln("%s", data);
}

auto replaceLast(string line, string toReplace){
    auto o = line.lastIndexOf(toReplace);
    return o >= 0 ? line[0..o] : line; 
} 

【讨论】:

    【解决方案4】:
    module main;
    import std.stdio : writeln;
    import std.string : lineSplitter, join;
    import std.algorithm : map, splitter, each;
    
    enum fcontent = "some text\r\nnext line\r\n";
    
    void main()
    {
        fcontent.lineSplitter.map!(a=>a.splitter(' ')
            .map!(b=>"'" ~ b ~ "'")
            .join(", "))
            .each!writeln;
    }
    

    【讨论】:

    • 认为的问题是,如果最后一个字符是 ',',如何删除字符串末尾的 ',' 字符?
    • 我的代码和原来的代码一样。但是从这个问题我不能说这是否是作者想要的
    【解决方案5】:

    看一下,我用这个扩展方法来替换任何最后一个字符或子字符串,例如:

    string testStr = "Happy holiday!";<br>
    
    Console.Write(testStr.ReplaceVeryLast("holiday!", "Easter!"));
    
    public static class StringExtensions
    {
        public static string ReplaceVeryLast(this string sStr, string sSearch, string sReplace = "")
        {
            int pos = 0;
    
            sStr = sStr.Trim();
    
            do
            {
                pos = sStr.LastIndexOf(sSearch, StringComparison.CurrentCultureIgnoreCase);
                if (pos >= 0 && pos + sSearch.Length == sStr.Length)
                    sStr = sStr.Substring(0, pos) + sReplace;
    
            } while (pos == (sStr.Length - sSearch.Length + 1));
    
            return sStr;
        }
    }
    

    【讨论】:

    • D 中的这个基本思想也很简单,我会用auto offset = str.lastIndexOf("thing-to-chop-off"); if(offset &gt;= 0) str = str[0 .. offset];
    • 如果您没有注意到:您的代码是 C#。 OP的代码在D中。
    猜你喜欢
    • 2021-12-11
    • 2011-11-18
    • 2011-12-15
    • 1970-01-01
    • 2016-04-16
    • 2020-03-12
    • 2017-08-19
    相关资源
    最近更新 更多