【问题标题】:Separate a PascalCase string into separate words using Dart?使用 Dart 将 PascalCase 字符串分成单独的单词?
【发布时间】:2021-02-16 16:28:18
【问题描述】:

我有一个词 HelloWorld 想拆分为 HelloWorld 那么我该如何在 Dart 中做到这一点?

目前,我有 -

String str = 'HelloWorld';

我不知道如何更进一步?

我试过RegExp喜欢

words = str.split(new RegExp(r"[A-Z]"));

但它不起作用。如何区分HelloWorld

【问题讨论】:

  • 试试这个(/(?<=[a-z])(?=[A-Z])/)
  • 遗憾的是,Dart 没有后视功能。它使用 ECMAScript 5 正则表达式。
  • @irn 我确实在dartpad.dartlang.org 上尝试过,它正在工作。您可以复制我在答案中添加的粘贴代码并检查。
  • 确认。我们存在差异,因为编译为 JavaScript 的 Dart 使用浏览器当前的 JavaScript RegExp 引擎,但原生 Dart(Flutter 使用的)基于 ECMAScript 5 RegExp 语法(它是几年前 V8 regexp 引擎的一个端口) .因此,从技术上讲,编译成 JavaScript 的 Dart 过于宽松,因为 Dart 不支持后视。

标签: regex dart flutter


【解决方案1】:

您想在大写字母之前拆分,第一个除外。 仅以大写字母(至少是 ASCII 字母)进行拆分很容易:

// Single character look-ahead for capital letter.
final beforeCapitalLetter = RegExp(r"(?=[A-Z])");
...
var parts = string.split(beforeCapitalLetter);

这里的问题是它也在第一个字母之前分裂,在结果部分中给你一个空的第一个元素。 如果你确定它在那里,你可以删除它。

if (parts.isNotEmpty && parts[0].isEmpty) parts = parts.sublist(1);

或者,您可以使用 RegExp 变得聪明:

// Matches before a capital letter that is not also at beginning of string.
final beforeNonLeadingCapitalLetter = RegExp(r"(?=(?!^)[A-Z])");
List<String> splitPascalCase(String input) =>
    input.split(beforeNonLeadingCapitalLetter);

示例结果:

print(splitPascalCase("HelloWorld"));  // [Hello, World]
print(splitPascalCase("One")); // [One]
print(splitPascalCase("none")); // [none]
print(splitPascalCase("BFG9000")); // [B, F, G9000]
print(splitPascalCase("XmlHTTPRequest")); // [Xml, H, T, T, P, Request]

(您可能要考虑最后一件事是否是您想要的)。

另一种选择是不拆分,而是匹配你想要的部分。

final pascalWords = RegExp(r"(?:[A-Z]+|^)[a-z]*");
List<String> getPascalWords(String input) =>
    pascalWords.allMatches(input).map((m) => m[0]).toList();

这会提取以一个或多个前导大写字母(或字符串开头)开头的所有单词。如果你的字符串只包含字母,它应该和前面的函数一样。如果它包含其他内容,则这些内容将被忽略。

print(getPascalWords("BFG9000")); // [BFG]
print(getPascalWords("XmlHTTPRequest")); // [Xml, HTTPRequest]

更喜欢哪一个取决于您希望获得哪些字符串作为输入,以及您希望如何处理边缘情况:相邻的大写字母?都是大写字母?空字符串?

如果它总是将一个或多个两个字母或更长的单词与第一个字母大写,那么它只是简单的情况,任何一种方法都可以。

编辑:自从首次发布以来,Dart RegExps 已经开始支持后视。这样,也可以通过拆分小写字母和大写字母来使用拆分,正如Serdnad 在评论中所说:

final _pascalWordsRE = RegExp(r"(?<=[a-z])(?=[A-Z])");
List<String> getPascalWords(String input) => pascalWords.split(_pascalWordsRE);

这在一个小写字母之后和一个大写字母之前分割。

【讨论】:

  • 非常感谢您的详尽回答。我用的是第二个:)
  • 为了不拆分 HTTP 等大写缩写,(?&lt;=[a-z])(?=[A-Z]) 检查下一个字母是否为大写,前一个字母是否为小写。
  • 谢谢。添加了使用lookbehind的选项。
【解决方案2】:

你可以试试这个

r"(?<=[a-z])(?=[A-Z])"

解释

  • (?&lt;=[a-z]) - 积极向后看。匹配任何小写字母。
  • (?=[A-Z]) - 正向前瞻。匹配任何大写字母。

    void main() {
    
       String str = 'HelloWorld';
       var words = str.split(new RegExp(r"(?<=[a-z])(?=[A-Z])"));
       print(words);
    }
    

打印 -> [Hello, World];

【讨论】:

  • 这在 DartPad 中运行良好,但由于某些奇怪的原因,它在 Flutter 中给了我一个错误。我确定这一定是我这边的错误。不过谢谢:)
  • 这是 Flutter 中的一个错误,因为 Dart RegExps 实际上不支持后视,但是编译为 JavaScript(DartPad 使用)的 Dart 将使用 JavaScript RegExp 实现。 Flutter 使用的原生 Dart RegExp 实现不支持 ECMAScript 5 之后添加到 JavaScript RegExps 的功能。
【解决方案3】:

titleCase 来自https://pub.dartlang.org/packages/recase 规定(除其他外)

var recase = ReCase(str);
print(recase.titleCase);

【讨论】:

  • 谢谢。总有一天我会使用 Recase。目前,接受的答案完成了工作:)
  • Lrn 的回答当然是最好的,但我认为 ReCase 是一个很好的工作建议。已经派上用场了好几次了,比如代码生成,你需要文件名、类名、导入,......从不同大小写中的单个名称生成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-19
  • 2020-07-30
  • 2018-05-09
  • 1970-01-01
  • 2010-12-06
  • 1970-01-01
相关资源
最近更新 更多