newlines.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2013 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Utilities for string newlines.
  16. * @author nnaze@google.com (Nathan Naze)
  17. */
  18. /**
  19. * Namespace for string utilities
  20. */
  21. goog.provide('goog.string.newlines');
  22. goog.provide('goog.string.newlines.Line');
  23. goog.require('goog.array');
  24. /**
  25. * Splits a string into lines, properly handling universal newlines.
  26. * @param {string} str String to split.
  27. * @param {boolean=} opt_keepNewlines Whether to keep the newlines in the
  28. * resulting strings. Defaults to false.
  29. * @return {!Array<string>} String split into lines.
  30. */
  31. goog.string.newlines.splitLines = function(str, opt_keepNewlines) {
  32. var lines = goog.string.newlines.getLines(str);
  33. return goog.array.map(lines, function(line) {
  34. return opt_keepNewlines ? line.getFullLine() : line.getContent();
  35. });
  36. };
  37. /**
  38. * Line metadata class that records the start/end indicies of lines
  39. * in a string. Can be used to implement common newline use cases such as
  40. * splitLines() or determining line/column of an index in a string.
  41. * Also implements methods to get line contents.
  42. *
  43. * Indexes are expressed as string indicies into string.substring(), inclusive
  44. * at the start, exclusive at the end.
  45. *
  46. * Create an array of these with goog.string.newlines.getLines().
  47. * @param {string} string The original string.
  48. * @param {number} startLineIndex The index of the start of the line.
  49. * @param {number} endContentIndex The index of the end of the line, excluding
  50. * newlines.
  51. * @param {number} endLineIndex The index of the end of the line, index
  52. * newlines.
  53. * @constructor
  54. * @struct
  55. * @final
  56. */
  57. goog.string.newlines.Line = function(
  58. string, startLineIndex, endContentIndex, endLineIndex) {
  59. /**
  60. * The original string.
  61. * @type {string}
  62. */
  63. this.string = string;
  64. /**
  65. * Index of the start of the line.
  66. * @type {number}
  67. */
  68. this.startLineIndex = startLineIndex;
  69. /**
  70. * Index of the end of the line, excluding any newline characters.
  71. * Index is the first character after the line, suitable for
  72. * String.substring().
  73. * @type {number}
  74. */
  75. this.endContentIndex = endContentIndex;
  76. /**
  77. * Index of the end of the line, excluding any newline characters.
  78. * Index is the first character after the line, suitable for
  79. * String.substring().
  80. * @type {number}
  81. */
  82. this.endLineIndex = endLineIndex;
  83. };
  84. /**
  85. * @return {string} The content of the line, excluding any newline characters.
  86. */
  87. goog.string.newlines.Line.prototype.getContent = function() {
  88. return this.string.substring(this.startLineIndex, this.endContentIndex);
  89. };
  90. /**
  91. * @return {string} The full line, including any newline characters.
  92. */
  93. goog.string.newlines.Line.prototype.getFullLine = function() {
  94. return this.string.substring(this.startLineIndex, this.endLineIndex);
  95. };
  96. /**
  97. * @return {string} The newline characters, if any ('\n', \r', '\r\n', '', etc).
  98. */
  99. goog.string.newlines.Line.prototype.getNewline = function() {
  100. return this.string.substring(this.endContentIndex, this.endLineIndex);
  101. };
  102. /**
  103. * Splits a string into an array of line metadata.
  104. * @param {string} str String to split.
  105. * @return {!Array<!goog.string.newlines.Line>} Array of line metadata.
  106. */
  107. goog.string.newlines.getLines = function(str) {
  108. // We use the constructor because literals are evaluated only once in
  109. // < ES 3.1.
  110. // See http://www.mail-archive.com/es-discuss@mozilla.org/msg01796.html
  111. var re = RegExp('\r\n|\r|\n', 'g');
  112. var sliceIndex = 0;
  113. var result;
  114. var lines = [];
  115. while (result = re.exec(str)) {
  116. var line = new goog.string.newlines.Line(
  117. str, sliceIndex, result.index, result.index + result[0].length);
  118. lines.push(line);
  119. // remember where to start the slice from
  120. sliceIndex = re.lastIndex;
  121. }
  122. // If the string does not end with a newline, add the last line.
  123. if (sliceIndex < str.length) {
  124. var line =
  125. new goog.string.newlines.Line(str, sliceIndex, str.length, str.length);
  126. lines.push(line);
  127. }
  128. return lines;
  129. };