diff --git a/core/includes/common.inc b/core/includes/common.inc
index f656206..b201ccc 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -59,7 +59,7 @@
  *
  * Correct:
  * @code
- *   $my_substring = drupal_substr($original_string, 0, 5);
+ *   $my_substring = Unicode::substr($original_string, 0, 5);
  * @endcode
  *
  * @}
diff --git a/core/includes/file.inc b/core/includes/file.inc
index f543c77..8d2ebbe 100644
--- a/core/includes/file.inc
+++ b/core/includes/file.inc
@@ -5,6 +5,7 @@
  * API for handling file uploads and server file management.
  */
 
+use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\PhpStorage\FileStorage;
 use Drupal\Component\Utility\Bytes;
@@ -316,7 +317,7 @@ function file_create_url($uri) {
     //   HTTP and to https://example.com/bar.jpg when viewing a HTTPS page)
     // Both types of relative URIs are characterized by a leading slash, hence
     // we can use a single check.
-    if (drupal_substr($uri, 0, 1) == '/') {
+    if (Unicode::substr($uri, 0, 1) == '/') {
       return $uri;
     }
     else {
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 303db67..1d977e5 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -11,6 +11,7 @@
 use Drupal\Component\Serialization\Json;
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Config\Config;
@@ -765,7 +766,7 @@ function theme_settings_convert_to_config(array $theme_settings, Config $config)
       $config->set('favicon.mimetype', $value);
     }
     else if (substr($key, 0, 7) == 'toggle_') {
-      $config->set('features.' . drupal_substr($key, 7), $value);
+      $config->set('features.' . Unicode::substr($key, 7), $value);
     }
     else if (!in_array($key, array('theme', 'logo_upload'))) {
       $config->set($key, $value);
diff --git a/core/lib/Drupal/Core/Updater/Updater.php b/core/lib/Drupal/Core/Updater/Updater.php
index 045a981..bbaecfb 100644
--- a/core/lib/Drupal/Core/Updater/Updater.php
+++ b/core/lib/Drupal/Core/Updater/Updater.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Updater;
 
+use Drupal\Component\Utility\Unicode;
 use Drupal\Core\FileTransfer\FileTransferException;
 use Drupal\Core\FileTransfer\FileTransferInterface;
 
@@ -100,7 +101,7 @@ public static function findInfoFile($directory) {
       return FALSE;
     }
     foreach ($info_files as $info_file) {
-      if (drupal_substr($info_file->filename, 0, -5) == drupal_basename($directory)) {
+      if (Unicode::substr($info_file->filename, 0, -5) == drupal_basename($directory)) {
         // Info file Has the same name as the directory, return it.
         return $info_file->uri;
       }
diff --git a/core/modules/dblog/src/Tests/DbLogTest.php b/core/modules/dblog/src/Tests/DbLogTest.php
index d397493..925e31a 100644
--- a/core/modules/dblog/src/Tests/DbLogTest.php
+++ b/core/modules/dblog/src/Tests/DbLogTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\dblog\Tests;
 
+use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Logger\RfcLogLevel;
 use Drupal\dblog\Controller\DbLogController;
@@ -305,7 +306,7 @@ private function doUser() {
       foreach ($links->attributes() as $attr => $value) {
         if ($attr == 'href') {
           // Extract link to details page.
-          $link = drupal_substr($value, strpos($value, 'admin/reports/dblog/event/'));
+          $link = Unicode::substr($value, strpos($value, 'admin/reports/dblog/event/'));
           $this->drupalGet($link);
           // Check for full message text on the details page.
           $this->assertRaw($message, 'DBLog event details was found: [delete user]');
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index d4a2253..f492e29 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -800,11 +800,11 @@ function _filter_html_image_secure_process($text) {
     // Verify that $src starts with $base_path.
     // This also ensures that external images cannot be referenced.
     $src = $image->getAttribute('src');
-    if (drupal_substr($src, 0, $base_path_length) === $base_path) {
+    if (Unicode::substr($src, 0, $base_path_length) === $base_path) {
       // Remove the $base_path to get the path relative to the Drupal root.
       // Ensure the path refers to an actual image by prefixing the image source
       // with the Drupal root and running getimagesize() on it.
-      $local_image_path = $local_dir . drupal_substr($src, $base_path_length);
+      $local_image_path = $local_dir . Unicode::substr($src, $base_path_length);
       $local_image_path = rawurldecode($local_image_path);
       if (@getimagesize($local_image_path)) {
         // The image has the right path. Erroneous images are dealt with below.
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index c622556..91afbc1 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -316,7 +316,7 @@ function search_expand_cjk($matches) {
   $chars = array();
   for ($i = 0; $i < $length; $i++) {
     // Add the next character off the beginning of the string to the queue.
-    $current = drupal_substr($str, 0, 1);
+    $current = Unicode::substr($str, 0, 1);
     $str = substr($str, strlen($current));
     $chars[] = $current;
     if ($i >= $min - 1) {
diff --git a/core/modules/search/src/Tests/SearchSimplifyTest.php b/core/modules/search/src/Tests/SearchSimplifyTest.php
index a850750..848f7b7 100644
--- a/core/modules/search/src/Tests/SearchSimplifyTest.php
+++ b/core/modules/search/src/Tests/SearchSimplifyTest.php
@@ -6,6 +6,7 @@
  */
 
 namespace Drupal\search\Tests;
+use Drupal\Component\Utility\Unicode;
 
 /**
  * Tests that the search_simply() function works as intended.
@@ -39,7 +40,7 @@ function testSearchSimplifyUnicode() {
         // of truncation in search_simplify().
         $start = 0;
         while ($start < drupal_strlen($string)) {
-          $newstr = drupal_substr($string, $start, 30);
+          $newstr = Unicode::substr($string, $start, 30);
           // Special case: leading zeros are removed from numeric strings,
           // and there's one string in this file that is numbers starting with
           // zero, so prepend a 1 on that string.
diff --git a/core/modules/system/src/Tests/Common/JavaScriptTest.php b/core/modules/system/src/Tests/Common/JavaScriptTest.php
index 8680765..a8a4874 100644
--- a/core/modules/system/src/Tests/Common/JavaScriptTest.php
+++ b/core/modules/system/src/Tests/Common/JavaScriptTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Tests\Common;
 
 use Drupal\Component\Serialization\Json;
+use Drupal\Component\Utility\Unicode;
 use Drupal\simpletest\DrupalUnitTestBase;
 use Drupal\Component\Utility\Crypt;
 
@@ -233,7 +234,7 @@ function testHeaderSetting() {
     $endToken = '}';
     $start = strpos($javascript, $startToken) + strlen($startToken);
     $end = strrpos($javascript, $endToken);
-    $json  = drupal_substr($javascript, $start, $end - $start + 1);
+    $json  = Unicode::substr($javascript, $start, $end - $start + 1);
     $parsed_settings = Json::decode($json);
 
     // Test whether the two real world cases are handled correctly.
diff --git a/core/modules/taxonomy/src/Tests/TermTest.php b/core/modules/taxonomy/src/Tests/TermTest.php
index 2915d2b..0900dce 100644
--- a/core/modules/taxonomy/src/Tests/TermTest.php
+++ b/core/modules/taxonomy/src/Tests/TermTest.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Serialization\Json;
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Tags;
+use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\field\Entity\FieldStorageConfig;
 use Drupal\taxonomy\Entity\Term;
@@ -535,7 +536,7 @@ function testTaxonomyGetTermByName() {
     $this->assertFalse($terms, 'No term loaded with an invalid name.');
 
     // Try to load the term using a substring of the name.
-    $terms = taxonomy_term_load_multiple_by_name(drupal_substr($term->getName(), 2), 'No term loaded with a substring of the name.');
+    $terms = taxonomy_term_load_multiple_by_name(Unicode::substr($term->getName(), 2), 'No term loaded with a substring of the name.');
     $this->assertFalse($terms);
 
     // Create a new term in a different vocabulary with the same name.
diff --git a/core/modules/user/src/Tests/UserAutocompleteTest.php b/core/modules/user/src/Tests/UserAutocompleteTest.php
index 204c496..a56c33c 100644
--- a/core/modules/user/src/Tests/UserAutocompleteTest.php
+++ b/core/modules/user/src/Tests/UserAutocompleteTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Tests;
 
 use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\Unicode;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -47,9 +48,9 @@ function testUserAutocomplete() {
     \Drupal::config('user.settings')->set('anonymous', $anonymous_name)->save();
     // Test that anonymous username is in the result when requested and escaped
     // with \Drupal\Component\Utility\String::checkPlain().
-    $users = $this->drupalGetJSON('user/autocomplete/anonymous', array('query' => array('q' => drupal_substr($anonymous_name, 0, 4))));
+    $users = $this->drupalGetJSON('user/autocomplete/anonymous', array('query' => array('q' => Unicode::substr($anonymous_name, 0, 4))));
     $this->assertEqual(String::checkPlain($anonymous_name), $users[0]['label'], 'The anonymous name found in autocompletion results.');
-    $users = $this->drupalGetJSON('user/autocomplete', array('query' => array('q' => drupal_substr($anonymous_name, 0, 4))));
+    $users = $this->drupalGetJSON('user/autocomplete', array('query' => array('q' => Unicode::substr($anonymous_name, 0, 4))));
     $this->assertTrue(empty($users), 'The anonymous name not found in autocompletion results without enabling anonymous username.');
   }
 }
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index 0cc5681..d8ff7ae 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\display;
 
 use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
@@ -1124,7 +1125,7 @@ public function optionsSummary(&$categories, &$options) {
       );
     }
 
-    $display_comment = String::checkPlain(drupal_substr($this->getOption('display_comment'), 0, 10));
+    $display_comment = String::checkPlain(Unicode::substr($this->getOption('display_comment'), 0, 10));
     $options['display_comment'] = array(
       'category' => 'other',
       'title' => $this->t('Administrative comment'),
diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
index d5df2fc..486ef5a 100644
--- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
+++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Form\FormStateInterface;
@@ -1281,7 +1282,7 @@ public function renderText($alter) {
         $base_path = base_path();
         // Checks whether the path starts with the base_path.
         if (strpos($more_link_path, $base_path) === 0) {
-          $more_link_path = drupal_substr($more_link_path, drupal_strlen($base_path));
+          $more_link_path = Unicode::substr($more_link_path, drupal_strlen($base_path));
         }
 
         $more_link = _l($more_link_text, $more_link_path, array('attributes' => array('class' => array('views-more-link'))));
@@ -1689,7 +1690,7 @@ public function adminLabel($short = FALSE) {
    */
   public static function trimText($alter, $value) {
     if (drupal_strlen($value) > $alter['max_length']) {
-      $value = drupal_substr($value, 0, $alter['max_length']);
+      $value = Unicode::substr($value, 0, $alter['max_length']);
       if (!empty($alter['word_boundary'])) {
         $regex = "(.*)\b.+";
         if (function_exists('mb_ereg')) {
diff --git a/core/modules/views/src/Tests/Handler/FieldWebTest.php b/core/modules/views/src/Tests/Handler/FieldWebTest.php
index cdb98dc..6b76422 100644
--- a/core/modules/views/src/Tests/Handler/FieldWebTest.php
+++ b/core/modules/views/src/Tests/Handler/FieldWebTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Tests\Handler;
 
+use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\views\Views;
 
@@ -480,7 +481,7 @@ public function testTextRendering() {
     // Tests for simple trimming by string length.
     $row->views_test_data_name = $this->randomMachineName(8);
     $name_field->options['alter']['max_length'] = 5;
-    $trimmed_name = drupal_substr($row->views_test_data_name, 0, 5);
+    $trimmed_name = Unicode::substr($row->views_test_data_name, 0, 5);
 
     $output = $name_field->advancedRender($row);
     $this->assertSubString($output, $trimmed_name, format_string('Make sure the trimmed output (!trimmed) appears in the rendered output (!output).', array('!trimmed' => $trimmed_name, '!output' => $output)));
diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module
index 94b45ea..a6a51e3 100644
--- a/core/modules/views_ui/views_ui.module
+++ b/core/modules/views_ui/views_ui.module
@@ -5,6 +5,7 @@
  * Provide structure for the administrative interface to Views.
  */
 
+use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
 use Drupal\views\Views;
@@ -327,7 +328,7 @@ function views_ui_views_analyze(ViewExecutable $view) {
  */
 function views_ui_truncate($string, $length) {
   if (drupal_strlen($string) > $length) {
-    $string = drupal_substr($string, 0, $length);
+    $string = Unicode::substr($string, 0, $length);
     $string .= '...';
   }
 
