【问题标题】:Reversing a string with escape characters使用转义字符反转字符串
【发布时间】:2017-12-04 16:39:18
【问题描述】:

我有一个可能包含转义字符的字符串。假设这是'\'。我关注MSDN Escape Sequences definition

我想反转这个字符串,但保留转义序列。

例子:

string input = @"Hello\_World";
string reversed = @"dlroW\_elloH";

请注意,在我的输入字符串中,反斜杠是单独的字符。反转的字符串用于 SQL LIKE 语句,其中下划线不是通配符,而是字面上的下划线。 SQL LIKE 中的反斜杠用作转义字符

问题是,如果我的原始字符串中的一个字符前面有一个反斜杠,那么在我的反向字符串中,这个反斜杠仍然应该在字符之前:@“_”(两个单独的字符)应该反过来仍然是 @” _”。

加分:使用数字 '\x0128' 的反向转义序列

我已经尝试将它作为扩展功能:

public static string EscapedReverse(this string txt, char escapeChar)
{
    IList<char> charList = txt.ToList();
    return new string(EscapedReverse(charList, escapeChar).ToArray());
}

public static IEnumerable<char> EscapedReverse(this IList<char> text, char escapeChar)
{
    int i = text.Count-1;
    // Text[i] is the last character of the sequence;
    // text[i] is the next character to return, except if text[i-1] is escapeChar
    while (i > 0)
    {
        if(text[i-1] == escapeChar)
        {
            yield return text[i-1];
            yield return text[i];
            i -= 2;
        }
        else
        {
            yield return text[i];
            i -= 1;
        }
    }
    // return the last character
    if (i == 0)
        yield return text[i];
}

这行得通。但是,我的字符串被转换为数组/列表两次。我想知道是否会有一种更智能的方法,不需要经常访问元素?

补充:我的问题是什么?

建议添加有关我的问题的更多信息的评论。

当操作员在文本框中键入时,需要显示匹配元素的列表。他能看到的大多数元素都以类似的前缀开头。运算符搜索的区别在于名称的末尾。

因此,我们希望显示一个名称列表结尾与键入的字符。因此,如果操作员键入“World”,他将看到一个列表,其中所有名称都以“World”结尾。

已经存在的数据库(更改是不可能的)有一个带有 NAME 和 REVERSEDNAME 的表。软件会注意如果插入或更新名称,则插入/更新正确的反向名称。 REVERSEDNAME 已编入索引,因此使用带有反向名称的 WHERE 会很快。

因此,如果我需要返回所有以“World”结尾的名称,则需要返回 REVERSEDNAME 以“WORLD”的倒数开头的所有记录的名称:

SELECT TOP 30 [MYTABLE].[NAME] as Name
FROM [MYTABLE]
WHERE [MYTABLE].REVERSEDNAME LIKE 'dlroW%'

只要不使用通配符(如下划线),它就可以正常工作。软件通过转义下划线字符解决了这个问题(我知道,糟糕的设计,SQL LIKE 使用下划线作为通配符的事实不应该渗透,但我必须忍受这个现有的软件)

所以运算符键入@"My_World" 我的软件收到@"My_World",反斜杠是单独的字符 我要反转到@"dlrow_yM",注意反斜杠还在下划线之前

我的 Dapper 代码:

IEnumerable<string> FetchNamesEndingWith(string nameEnd)

// here is my reversal procedure:
string reversedNameEnd = nameEnd.EscapedReverse() = '%';

using (var dbConnection = this.CreateOpenDbConnection())
{
    return dbConnection.Query<string>(@"
        SELECT TOP 30 [MYTABLE].[NAME] as Name
        FROM [MYTABLE]
        WHERE [MYTABLE].REVERSEDNAME LIKE @param ESCAPE '\'",
        new {param = reversedNameEnd});
}

MSDN about using escape characters in SQL LIKE

将转义字符更改为其他字符无济于事。问题不在于转义字符是反斜杠,而是反转我的字符串应该将转义字符保持在转义字符的前面。

我的代码有效,我只是想知道是否会有更好的算法不会复制字符串两次。不仅针对这个特定问题,而且如果在将来的问题中我需要反转字符串并将某些字符保留在适当的位置。

【问题讨论】:

  • 如果你的方法有效,问题是题外话,你可能想把它发到codereview.stackexchange.com
  • 旁注:为什么你的方法接受IList&lt;char&gt;而不是string。整个方法仍然有效,您不必从文本创建列表来调用它。
  • 如果字符串是这样定义的,则反斜杠不会出现在字符串中,因为\t 表示制表符,\" 表示引号。你确定你在这里甚至问题吗?可以发minimal reproducible example吗?
  • 你说的对,忘记加介绍@了。问题是在 LIKE 中带有下划线的 SqlCommand,表示通配符。我想匹配名称的结尾部分,所以我必须将 LIKE 与反转部分进行比较。我会相应地编辑我的问题

标签: c# string reverse


【解决方案1】:

你可以使用正则表达式:

var pattern =  @"\\x[1-9a-fA-F]{4}|\\x[1-9a-fA-F]{2}|\\[0-7]{3}|\\.|.";
var rgx = new Regex(pattern);
return new string(
          rgx.Matches(txt)
          .Cast<Match>()
          .OrderByDescending(x => x.Index)
          .SelectMany(x => x.Value)
          .ToArray());

pattern 涵盖格式中的单个字符和转义序列:

\x????
\x??
\???
\?

【讨论】:

  • 好答案!我建议将模式更改为 @"\(a|b|f|n|r|t|v|'|""|\\|\?|[0-7]{3}|(x[0-9a -fA-F]{4})|(x[0-9a-fA-F]{2}))|。”所以它只会对 msdn 指定的转义序列产生影响
  • @GuyMontag 实际上根据msdn:如果反斜杠位于表中未出现的字符之前,编译器会将未定义的字符作为字符本身处理。因此,您的建议将对单字母转义序列产生无效结果。在 \x 值上很好地捕获十六进制。
  • 公平点。最后一件事:我认为第三个选择应该读取 \[0-7]{3} 以便仅匹配三位 ASCII 字符的八进制数
  • @GuyMontag 真实。
  • 代码可能更短,但对于审阅者来说更难检查。正则表达式会比我当前的代码复制两次更快吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多