replace.hpp 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #pragma once
  2. namespace nall {
  3. template<bool Insensitive, bool Quoted>
  4. auto string::_replace(string_view from, string_view to, long limit) -> string& {
  5. if(limit <= 0 || from.size() == 0) return *this;
  6. int size = this->size();
  7. int matches = 0;
  8. int quoted = 0;
  9. //count matches first, so that we only need to reallocate memory once
  10. //(recording matches would also require memory allocation, so this is not done)
  11. { const char* p = data();
  12. for(int n = 0; n <= size - (int)from.size();) {
  13. if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
  14. if(_compare<Insensitive>(p + n, size - n, from.data(), from.size())) { n++; continue; }
  15. if(++matches >= limit) break;
  16. n += from.size();
  17. }
  18. }
  19. if(matches == 0) return *this;
  20. //in-place overwrite
  21. if(to.size() == from.size()) {
  22. char* p = get();
  23. for(int n = 0, remaining = matches, quoted = 0; n <= size - (int)from.size();) {
  24. if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
  25. if(_compare<Insensitive>(p + n, size - n, from.data(), from.size())) { n++; continue; }
  26. memory::copy(p + n, to.data(), to.size());
  27. if(!--remaining) break;
  28. n += from.size();
  29. }
  30. }
  31. //left-to-right shrink
  32. else if(to.size() < from.size()) {
  33. char* p = get();
  34. int offset = 0;
  35. int base = 0;
  36. for(int n = 0, remaining = matches, quoted = 0; n <= size - (int)from.size();) {
  37. if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
  38. if(_compare<Insensitive>(p + n, size - n, from.data(), from.size())) { n++; continue; }
  39. if(offset) memory::move(p + offset, p + base, n - base);
  40. memory::copy(p + offset + (n - base), to.data(), to.size());
  41. offset += (n - base) + to.size();
  42. n += from.size();
  43. base = n;
  44. if(!--remaining) break;
  45. }
  46. memory::move(p + offset, p + base, size - base);
  47. resize(size - matches * (from.size() - to.size()));
  48. }
  49. //right-to-left expand
  50. else if(to.size() > from.size()) {
  51. resize(size + matches * (to.size() - from.size()));
  52. char* p = get();
  53. int offset = this->size();
  54. int base = size;
  55. for(int n = size, remaining = matches; n >= (int)from.size();) { //quoted reused from parent scope since we are iterating backward
  56. if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n--; continue; } if(quoted) { n--; continue; } }
  57. if(_compare<Insensitive>(p + n - from.size(), size - n + from.size(), from.data(), from.size())) { n--; continue; }
  58. memory::move(p + offset - (base - n), p + base - (base - n), base - n);
  59. memory::copy(p + offset - (base - n) - to.size(), to.data(), to.size());
  60. offset -= (base - n) + to.size();
  61. if(!--remaining) break;
  62. n -= from.size();
  63. base = n;
  64. }
  65. }
  66. return *this;
  67. }
  68. auto string::replace(string_view from, string_view to, long limit) -> string& { return _replace<0, 0>(from, to, limit); }
  69. auto string::ireplace(string_view from, string_view to, long limit) -> string& { return _replace<1, 0>(from, to, limit); }
  70. auto string::qreplace(string_view from, string_view to, long limit) -> string& { return _replace<0, 1>(from, to, limit); }
  71. auto string::iqreplace(string_view from, string_view to, long limit) -> string& { return _replace<1, 1>(from, to, limit); }
  72. };