【问题标题】:How to split a string with newlines如何用换行符分割字符串
【发布时间】:2013-02-15 21:01:18
【问题描述】:

我从一个 csv 文件中读取数据,并希望使用 stringWithContentsOfFile 拆分我得到的长字符串,它是一个多行字符串,其中单独的行代表 csv 文件中的行。我该怎么做?

【问题讨论】:

  • 为什么要将整个文件加载到内存中?这对你的内存占用没有任何帮助......
  • 也许已知文件不会那么大。它只是文本...
  • 是的...文件足够小...它只有 54 行和 4 列!

标签: ios nsstring newline


【解决方案1】:

以防万一有人像我一样偶然发现这个问题。这适用于任何换行符:

NSCharacterSet *separator = [NSCharacterSet newlineCharacterSet];
NSArray *rows = [yourString componentsSeparatedByCharactersInSet:separator];

【讨论】:

  • 如果行分隔符是\r\n(两个字符),这会在数组中产生空字符串,就像在 Windows 格式的文件中一样。
【解决方案2】:

您可以将字符串分解为字符串数组,然后根据需要进行操作。

NSArray *brokenByLines=[yourString componentsSeparatedByString:@"\n"]

【讨论】:

  • 这对行分隔符做了很多假设。
  • 如果你不知道行分隔符是什么:let lines = stringData.stringByReplacingOccurrencesOfString("\r\n", withString: "\"n").stringByReplacingOccurrencesOfString("\r", withString: "\n").componentsSeparatedByString("\n")
  • 一个不必替换@"\r",如果字符串用newLineCharacterSet分隔;
【解决方案3】:

您应该知道\n 不是用于分割新行的唯一字符。例如,如果文件保存在 Windows 中,则换行符将为 \r\n。阅读the Newline article in Wikipedia 了解更多信息。

因此,如果你只使用componentsSeparatedByString("\n"),你可能会得到意想不到的结果。

let multiLineString = "Line 1\r\nLine 2\r\nLine 3\r\n"
let lineArray = multiLineStringRN.componentsSeparatedByString("\n")
// ["Line 1\r", "Line 2\r", "Line 3\r", ""]

注意剩余的\r 和空数组元素。

有几种方法可以避免这些问题。

解决方案

1. componentsSeparatedByCharactersInSet

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let newlineChars = NSCharacterSet.newlineCharacterSet()
let lineArray = multiLineString.componentsSeparatedByCharactersInSet(newlineChars).filter{!$0.isEmpty}
// "[Line 1, Line 2, Line 3]"

如果未使用filter,则\r\n 将生成一个空数组元素,因为它被计为两个字符,因此在同一位置将字符串分隔两次。

2。 split

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let newlineChars = NSCharacterSet.newlineCharacterSet()
let lineArray = multiLineString.utf16.split { newlineChars.characterIsMember($0) }.flatMap(String.init)
// "[Line 1, Line 2, Line 3]"

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let lineArray = multiLineString.characters.split { $0 == "\n" || $0 == "\r\n" }.map(String.init)
// "[Line 1, Line 2, Line 3]"

这里 \r\n 被视为单个 Swift 字符(扩展的字素簇)

3. enumerateLines

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
var lineArray = [String]()
multiLineString.enumerateLines { (line, stop) -> () in
    lineArray.append(line)
}
// "[Line 1, Line 2, Line 3]"

有关enumerateLine 语法的更多信息,另请参阅this answer

注意事项:

  • 多行字符串通常不会同时混合\r\n\n,但我在这里这样做是为了表明这些方法可以处理这两种格式。
  • NSCharacterSet.newlineCharacterSet() 是定义为 (U+000A–U+000D, U+0085) 的换行符,包括 \r\n
  • 此答案是对my previous question 的答案的摘要。阅读这些答案以了解更多详情。

【讨论】:

    【解决方案4】:

    Swift 3 版本:

    let lines = yourString.components(separatedBy: .newlines)
    

    又好又短。

    【讨论】:

      【解决方案5】:

      您需要用“\n”分隔您的内容。

          NSString *str= [NSString stringWithContentsOfFile:filePathLib encoding:NSUTF8StringEncoding error:nil];
          NSArray *rows = [str componentsSeparatedByString:@"\n"];
      
          for(int i =0;i<[rows count];i++)
              NSLog(@"Row %d: %@",i,[rows objectAtIndex:i]);
      

      【讨论】:

      • 这也是对行分隔符的假设。
      【解决方案6】:

      这是我的看法:

          NSString* string = @"FOO\r\nBAR\r\r\n\rATZ\rELM327 v1.5";
          NSCharacterSet* newlineSet = [NSCharacterSet newlineCharacterSet];
          NSCharacterSet* whitespaceSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
          NSArray<NSString*>* components = [string componentsSeparatedByCharactersInSet:newlineSet];
          NSPredicate* predicate = [NSPredicate predicateWithBlock:^BOOL(NSString* _Nullable string, NSDictionary<NSString *,id> * _Nullable bindings){
              return [string stringByTrimmingCharactersInSet:whitespaceSet].length > 0;
          }];
          NSArray<NSString*>* lines = [components filteredArrayUsingPredicate:predicate];
      
          [lines enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
              NSLog( @"Line %u = '%@'", idx, obj );
          }];
      

      运行此打印:

      2017-10-24 15:26:05.380 Untitled 5[64977:3182818] Line 0 = 'FOO'
      2017-10-24 15:26:05.380 Untitled 5[64977:3182818] Line 1 = 'BAR'
      2017-10-24 15:26:05.380 Untitled 5[64977:3182818] Line 2 = 'ATZ'
      2017-10-24 15:26:05.380 Untitled 5[64977:3182818] Line 3 = 'ELM327 v1.5'
      

      这可能不是最有效的方法(可能使用NSScanner 会更快),但它解决了这里的问题。

      【讨论】:

      • 我最喜欢您的回答,因为它既解决了许多新行场景,又清理了输出,并为 NSScanner 敞开了大门。我认为它甚至可以很好地包装为 NSString 类别 NSString+lines 并提供 * 行;方法...
      猜你喜欢
      • 2022-07-06
      • 2013-11-15
      • 1970-01-01
      • 1970-01-01
      • 2015-11-08
      • 2021-01-10
      • 1970-01-01
      • 2012-07-07
      • 2014-09-23
      相关资源
      最近更新 更多