Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Side by Side Diff: base/strings/string_util.cc

Issue 1200393002: Add more string_util functions to base namespace. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@string
Patch Set: Android Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/strings/string_util.h ('k') | base/trace_event/trace_event_android.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/strings/string_util.h" 5 #include "base/strings/string_util.h"
6 6
7 #include <ctype.h> 7 #include <ctype.h>
8 #include <errno.h> 8 #include <errno.h>
9 #include <math.h> 9 #include <math.h>
10 #include <stdarg.h> 10 #include <stdarg.h>
(...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount, 652 base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount,
653 kByteStringsUnlocalized[dimension]); 653 kByteStringsUnlocalized[dimension]);
654 } else { 654 } else {
655 base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount, 655 base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount,
656 kByteStringsUnlocalized[dimension]); 656 kByteStringsUnlocalized[dimension]);
657 } 657 }
658 658
659 return ASCIIToUTF16(buf); 659 return ASCIIToUTF16(buf);
660 } 660 }
661 661
662 } // namespace base
663
664 // Runs in O(n) time in the length of |str|. 662 // Runs in O(n) time in the length of |str|.
665 template<class StringType> 663 template<class StringType>
666 void DoReplaceSubstringsAfterOffset(StringType* str, 664 void DoReplaceSubstringsAfterOffset(StringType* str,
667 size_t offset, 665 size_t offset,
668 const StringType& find_this, 666 BasicStringPiece<StringType> find_this,
669 const StringType& replace_with, 667 BasicStringPiece<StringType> replace_with,
670 bool replace_all) { 668 bool replace_all) {
671 DCHECK(!find_this.empty()); 669 DCHECK(!find_this.empty());
672 670
673 // If the find string doesn't appear, there's nothing to do. 671 // If the find string doesn't appear, there's nothing to do.
674 offset = str->find(find_this, offset); 672 offset = str->find(find_this.data(), offset, find_this.size());
675 if (offset == StringType::npos) 673 if (offset == StringType::npos)
676 return; 674 return;
677 675
678 // If we're only replacing one instance, there's no need to do anything 676 // If we're only replacing one instance, there's no need to do anything
679 // complicated. 677 // complicated.
680 size_t find_length = find_this.length(); 678 size_t find_length = find_this.length();
681 if (!replace_all) { 679 if (!replace_all) {
682 str->replace(offset, find_length, replace_with); 680 str->replace(offset, find_length, replace_with.data(), replace_with.size());
683 return; 681 return;
684 } 682 }
685 683
686 // If the find and replace strings are the same length, we can simply use 684 // If the find and replace strings are the same length, we can simply use
687 // replace() on each instance, and finish the entire operation in O(n) time. 685 // replace() on each instance, and finish the entire operation in O(n) time.
688 size_t replace_length = replace_with.length(); 686 size_t replace_length = replace_with.length();
689 if (find_length == replace_length) { 687 if (find_length == replace_length) {
690 do { 688 do {
691 str->replace(offset, find_length, replace_with); 689 str->replace(offset, find_length,
692 offset = str->find(find_this, offset + replace_length); 690 replace_with.data(), replace_with.size());
691 offset = str->find(find_this.data(), offset + replace_length,
692 find_this.size());
693 } while (offset != StringType::npos); 693 } while (offset != StringType::npos);
694 return; 694 return;
695 } 695 }
696 696
697 // Since the find and replace strings aren't the same length, a loop like the 697 // Since the find and replace strings aren't the same length, a loop like the
698 // one above would be O(n^2) in the worst case, as replace() will shift the 698 // one above would be O(n^2) in the worst case, as replace() will shift the
699 // entire remaining string each time. We need to be more clever to keep 699 // entire remaining string each time. We need to be more clever to keep
700 // things O(n). 700 // things O(n).
701 // 701 //
702 // If we're shortening the string, we can alternate replacements with shifting 702 // If we're shortening the string, we can alternate replacements with shifting
703 // forward the intervening characters using memmove(). 703 // forward the intervening characters using memmove().
704 size_t str_length = str->length(); 704 size_t str_length = str->length();
705 if (find_length > replace_length) { 705 if (find_length > replace_length) {
706 size_t write_offset = offset; 706 size_t write_offset = offset;
707 do { 707 do {
708 if (replace_length) { 708 if (replace_length) {
709 str->replace(write_offset, replace_length, replace_with); 709 str->replace(write_offset, replace_length,
710 replace_with.data(), replace_with.size());
710 write_offset += replace_length; 711 write_offset += replace_length;
711 } 712 }
712 size_t read_offset = offset + find_length; 713 size_t read_offset = offset + find_length;
713 offset = std::min(str->find(find_this, read_offset), str_length); 714 offset = std::min(
715 str->find(find_this.data(), read_offset, find_this.size()),
716 str_length);
714 size_t length = offset - read_offset; 717 size_t length = offset - read_offset;
715 if (length) { 718 if (length) {
716 memmove(&(*str)[write_offset], &(*str)[read_offset], 719 memmove(&(*str)[write_offset], &(*str)[read_offset],
717 length * sizeof(typename StringType::value_type)); 720 length * sizeof(typename StringType::value_type));
718 write_offset += length; 721 write_offset += length;
719 } 722 }
720 } while (offset < str_length); 723 } while (offset < str_length);
721 str->resize(write_offset); 724 str->resize(write_offset);
722 return; 725 return;
723 } 726 }
724 727
725 // We're lengthening the string. We can use alternating replacements and 728 // We're lengthening the string. We can use alternating replacements and
726 // memmove() calls like above, but we need to precalculate the final string 729 // memmove() calls like above, but we need to precalculate the final string
727 // length and then expand from back-to-front to avoid overwriting the string 730 // length and then expand from back-to-front to avoid overwriting the string
728 // as we're reading it, needing to shift, or having to copy to a second string 731 // as we're reading it, needing to shift, or having to copy to a second string
729 // temporarily. 732 // temporarily.
730 size_t first_match = offset; 733 size_t first_match = offset;
731 734
732 // First, calculate the final length and resize the string. 735 // First, calculate the final length and resize the string.
733 size_t final_length = str_length; 736 size_t final_length = str_length;
734 size_t expansion = replace_length - find_length; 737 size_t expansion = replace_length - find_length;
735 size_t current_match; 738 size_t current_match;
736 do { 739 do {
737 final_length += expansion; 740 final_length += expansion;
738 // Minor optimization: save this offset into |current_match|, so that on 741 // Minor optimization: save this offset into |current_match|, so that on
739 // exit from the loop, |current_match| will point at the last instance of 742 // exit from the loop, |current_match| will point at the last instance of
740 // the find string, and we won't need to find() it again immediately. 743 // the find string, and we won't need to find() it again immediately.
741 current_match = offset; 744 current_match = offset;
742 offset = str->find(find_this, offset + find_length); 745 offset = str->find(find_this.data(), offset + find_length,
746 find_this.size());
743 } while (offset != StringType::npos); 747 } while (offset != StringType::npos);
744 str->resize(final_length); 748 str->resize(final_length);
745 749
746 // Now do the replacement loop, working backwards through the string. 750 // Now do the replacement loop, working backwards through the string.
747 for (size_t prev_match = str_length, write_offset = final_length; ; 751 for (size_t prev_match = str_length, write_offset = final_length; ;
748 current_match = str->rfind(find_this, current_match - 1)) { 752 current_match = str->rfind(find_this.data(), current_match - 1,
753 find_this.size())) {
749 size_t read_offset = current_match + find_length; 754 size_t read_offset = current_match + find_length;
750 size_t length = prev_match - read_offset; 755 size_t length = prev_match - read_offset;
751 if (length) { 756 if (length) {
752 write_offset -= length; 757 write_offset -= length;
753 memmove(&(*str)[write_offset], &(*str)[read_offset], 758 memmove(&(*str)[write_offset], &(*str)[read_offset],
754 length * sizeof(typename StringType::value_type)); 759 length * sizeof(typename StringType::value_type));
755 } 760 }
756 write_offset -= replace_length; 761 write_offset -= replace_length;
757 str->replace(write_offset, replace_length, replace_with); 762 str->replace(write_offset, replace_length,
763 replace_with.data(), replace_with.size());
758 if (current_match == first_match) 764 if (current_match == first_match)
759 return; 765 return;
760 prev_match = current_match; 766 prev_match = current_match;
761 } 767 }
762 } 768 }
763 769
764 void ReplaceFirstSubstringAfterOffset(string16* str, 770 void ReplaceFirstSubstringAfterOffset(string16* str,
765 size_t start_offset, 771 size_t start_offset,
766 const string16& find_this, 772 StringPiece16 find_this,
767 const string16& replace_with) { 773 StringPiece16 replace_with) {
768 DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, 774 DoReplaceSubstringsAfterOffset<string16>(
769 false); // replace first instance 775 str, start_offset, find_this, replace_with, false); // Replace first.
770 } 776 }
771 777
772 void ReplaceFirstSubstringAfterOffset(std::string* str, 778 void ReplaceFirstSubstringAfterOffset(std::string* str,
773 size_t start_offset, 779 size_t start_offset,
774 const std::string& find_this, 780 StringPiece find_this,
775 const std::string& replace_with) { 781 StringPiece replace_with) {
776 DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, 782 DoReplaceSubstringsAfterOffset<std::string>(
777 false); // replace first instance 783 str, start_offset, find_this, replace_with, false); // Replace first.
778 } 784 }
779 785
780 void ReplaceSubstringsAfterOffset(string16* str, 786 void ReplaceSubstringsAfterOffset(string16* str,
781 size_t start_offset, 787 size_t start_offset,
782 const string16& find_this, 788 StringPiece16 find_this,
783 const string16& replace_with) { 789 StringPiece16 replace_with) {
784 DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, 790 DoReplaceSubstringsAfterOffset<string16>(
785 true); // replace all instances 791 str, start_offset, find_this, replace_with, true); // Replace all.
786 } 792 }
787 793
788 void ReplaceSubstringsAfterOffset(std::string* str, 794 void ReplaceSubstringsAfterOffset(std::string* str,
789 size_t start_offset, 795 size_t start_offset,
790 const std::string& find_this, 796 StringPiece find_this,
791 const std::string& replace_with) { 797 StringPiece replace_with) {
792 DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, 798 DoReplaceSubstringsAfterOffset<std::string>(
793 true); // replace all instances 799 str, start_offset, find_this, replace_with, true); // Replace all.
794 } 800 }
795 801
802 } // namespace base
803
796 size_t Tokenize(const base::string16& str, 804 size_t Tokenize(const base::string16& str,
797 const base::string16& delimiters, 805 const base::string16& delimiters,
798 std::vector<base::string16>* tokens) { 806 std::vector<base::string16>* tokens) {
799 *tokens = base::SplitString( 807 *tokens = base::SplitString(
800 str, delimiters, base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); 808 str, delimiters, base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
801 return tokens->size(); 809 return tokens->size();
802 } 810 }
803 811
804 size_t Tokenize(const std::string& str, 812 size_t Tokenize(const std::string& str,
805 const std::string& delimiters, 813 const std::string& delimiters,
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
1118 } 1126 }
1119 1127
1120 } // namespace 1128 } // namespace
1121 1129
1122 size_t base::strlcpy(char* dst, const char* src, size_t dst_size) { 1130 size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
1123 return lcpyT<char>(dst, src, dst_size); 1131 return lcpyT<char>(dst, src, dst_size);
1124 } 1132 }
1125 size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) { 1133 size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
1126 return lcpyT<wchar_t>(dst, src, dst_size); 1134 return lcpyT<wchar_t>(dst, src, dst_size);
1127 } 1135 }
OLDNEW
« no previous file with comments | « base/strings/string_util.h ('k') | base/trace_event/trace_event_android.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698