Index: src/wp-includes/js/shortcode.js
===================================================================
--- src/wp-includes/js/shortcode.js	(revision 34910)
+++ src/wp-includes/js/shortcode.js	(working copy)
@@ -135,7 +135,7 @@
 			// 6. an unquoted value.
 			// 7. A numeric attribute in double quotes.
 			// 8. An unquoted numeric attribute.
-			pattern = /(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/g;
+			pattern = /([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*'([^']*)'(?:\s|$)|([\w-]+)\s*=\s*([^\s'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/g;
 
 			// Map zero-width spaces to actual spaces.
 			text = text.replace( /[\u00a0\u200b]/g, ' ' );
Index: tests/phpunit/tests/shortcode.php
===================================================================
--- tests/phpunit/tests/shortcode.php	(revision 34910)
+++ tests/phpunit/tests/shortcode.php	(working copy)
@@ -632,4 +632,18 @@
 		require_once( DIR_TESTDATA . '/formatting/whole-posts.php' );
 		return data_whole_posts();
 	}
+
+	function test_php_and_js_shortcode_attribute_regexes_match() {
+
+		$file = file_get_contents( ABSPATH . WPINC . '/js/shortcode.js' );
+		$matched = preg_match( '|\s+pattern = (\/.+\/)g;|', $file, $matches );
+		$php = get_shortcode_atts_regex();
+
+		$this->assertSame( 1, $matched );
+
+		$js = str_replace( "\'", "'", $matches[1] );
+		$this->assertSame( $php, $js );
+
+	}
+
 }
Index: src/wp-includes/shortcodes.php
===================================================================
--- src/wp-includes/shortcodes.php	(revision 34910)
+++ src/wp-includes/shortcodes.php	(working copy)
@@ -451,6 +451,17 @@
 }
 
 /**
+ * Retrieve the shortcode attributes regex.
+ *
+ * @since 4.4.0
+ *
+ * @return string The shortcode attribute regular expression
+ */
+function get_shortcode_atts_regex() {
+	return '/([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*\'([^\']*)\'(?:\s|$)|([\w-]+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/';
+}
+
+/**
  * Retrieve all attributes from the shortcodes tag.
  *
  * The attributes list has the attribute name as the key and the value of the
@@ -467,7 +478,7 @@
  */
 function shortcode_parse_atts($text) {
 	$atts = array();
-	$pattern = '/([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*\'([^\']*)\'(?:\s|$)|([\w-]+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/';
+	$pattern = get_shortcode_atts_regex();
 	$text = preg_replace("/[\x{00a0}\x{200b}]+/u", " ", $text);
 	if ( preg_match_all($pattern, $text, $match, PREG_SET_ORDER) ) {
 		foreach ($match as $m) {
