Comment extraire deux chiffres consécutifs d'un champ de texte dans MySQL?

j'ai une base de données MySQL et j'ai une requête comme:

SELECT `id`, `originaltext` FROM `source` WHERE `originaltext` regexp '[0-9][0-9]'

cela détecte tous les textes originaux qui ont des numéros à 2 chiffres.

J'ai besoin de MySQL pour retourner ces nombres comme un champ , afin que je puisse les manipuler davantage.

idéalement, si je peux ajouter des critères supplémentaires qui devraient être > 20 serait grand, mais je peux le faire séparément aussi bien.

27
demandé sur Steve Chambers 2011-03-19 13:14:05

6 réponses

si vous voulez plus de puissance d'expression régulière dans votre base de données, vous pouvez envisager d'utiliser LIB_MYSQLUDF_PREG . Il s'agit d'une bibliothèque libre de fonctions utilisateur MySQL qui importe la bibliothèque PCRE. LIB_MYSQLUDF_PREG est livré sous forme de code source seulement. Pour l'utiliser, vous devez être capable de le compiler et de l'installer dans votre serveur MySQL. L'installation de cette bibliothèque ne change en rien le support regex intégré de MySQL. Il ne fait que les informations supplémentaires suivantes fonctions disponibles:

PREG_CAPTURE extrait une correspondance regex d'une chaîne. PREG_POSITION renvoie la position à laquelle une expression régulière correspond à une chaîne. PREG_REPLACE effectue une recherche-et-replace sur une chaîne. PREG_RLIKE teste si un regex correspond à une chaîne.

Toutes ces fonctions prennent une expression régulière comme premier paramètre. Cette expression régulière doit être formatée comme un opérateur D'expression régulière Perl. Par exemple: pour tester si regex correspond insensiblement au cas du sujet, vous utiliserez le code MySQL PREG_RLIKE('/regex/i', sujet). Ceci est similaire aux fonctions preg de PHP, qui nécessitent également les délimiteurs supplémentaires // pour les expressions régulières à l'intérieur de la chaîne PHP.

si vous voulez quelque chose de plus simple, vous pouvez modifier cette fonction pour mieux répondre à vos besoins.

CREATE FUNCTION REGEXP_EXTRACT(string TEXT, exp TEXT)
-- Extract the first longest string that matches the regular expression
-- If the string is 'ABCD', check all strings and see what matches: 'ABCD', 'ABC', 'AB', 'A', 'BCD', 'BC', 'B', 'CD', 'C', 'D'
-- It's not smart enough to handle things like (A)|(BCD) correctly in that it will return the whole string, not just the matching token.

RETURNS TEXT
DETERMINISTIC
BEGIN
  DECLARE s INT DEFAULT 1;
  DECLARE e INT;
  DECLARE adjustStart TINYINT DEFAULT 1;
  DECLARE adjustEnd TINYINT DEFAULT 1;

  -- Because REGEXP matches anywhere in the string, and we only want the part that matches, adjust the expression to add '^' and '$'
  -- Of course, if those are already there, don't add them, but change the method of extraction accordingly.

  IF LEFT(exp, 1) = '^' THEN 
    SET adjustStart = 0;
  ELSE
    SET exp = CONCAT('^', exp);
  END IF;

  IF RIGHT(exp, 1) = '$' THEN
    SET adjustEnd = 0;
  ELSE
    SET exp = CONCAT(exp, '$');
  END IF;

  -- Loop through the string, moving the end pointer back towards the start pointer, then advance the start pointer and repeat
  -- Bail out of the loops early if the original expression started with '^' or ended with '$', since that means the pointers can't move
  WHILE (s <= LENGTH(string)) DO
    SET e = LENGTH(string);
    WHILE (e >= s) DO
      IF SUBSTRING(string, s, e) REGEXP exp THEN
        RETURN SUBSTRING(string, s, e);
      END IF;
      IF adjustEnd THEN
        SET e = e - 1;
      ELSE
        SET e = s - 1; -- ugh, such a hack to end it early
      END IF;
    END WHILE;
    IF adjustStart THEN
      SET s = s + 1;
    ELSE
      SET s = LENGTH(string) + 1; -- ugh, such a hack to end it early
    END IF;
  END WHILE;

  RETURN NULL;

END
12
répondu Pentium10 2014-12-05 19:33:11

il n'y a pas de syntaxe dans MySQL pour extraire du texte en utilisant des expressions régulières. Vous pouvez utiliser le REGEXP pour identifier les lignes contenant deux chiffres consécutifs, mais pour les extraire vous devez utiliser les fonctions ordinaires de manipulation de chaîne de caractères qui est très difficile dans ce cas.

solutions de rechange":

  • sélectionnez la valeur entière de la base de données puis utilisez une expression régulière sur le client.
  • utiliser un autre base de données qui a une meilleure prise en charge de la norme SQL (peut ne pas être une option, Je sais). Vous pouvez alors utiliser ceci: SUBSTRING(originaltext from '%#[0-9]{2}#%' for '#') .
9
répondu Mark Byers 2011-03-19 10:31:48

j'ai le même problème, et c'est la solution que j'ai trouvée (mais ça ne marchera pas dans tous les cas):

  • utilisez LOCATE() pour trouver le début et la fin de la chaîne que vous ne voulez pas correspondre
  • utiliser MID() pour extraire le substrat entre les deux...
  • garder la regexp pour correspondre uniquement les lignes où vous êtes sûr de trouver une correspondance.
2
répondu Greg 2012-10-26 09:54:06

j'ai utilisé mon code comme une procédure stockée (fonction), doit fonctionner pour extraire tout nombre construit à partir de chiffres dans un seul bloc. C'est une partie de mes plus large de la bibliothèque.

DELIMITER $$

--  2013.04 michal@glebowski.pl
--  FindNumberInText("ab 234 95 cd", TRUE) => 234  
--  FindNumberInText("ab 234 95 cd", FALSE) => 95

DROP FUNCTION IF EXISTS FindNumberInText$$
CREATE FUNCTION FindNumberInText(_input VARCHAR(64), _fromLeft BOOLEAN) RETURNS VARCHAR(32)
BEGIN
  DECLARE _r              VARCHAR(32) DEFAULT '';
  DECLARE _i              INTEGER DEFAULT 1;
  DECLARE _start          INTEGER DEFAULT 0;
  DECLARE _IsCharNumeric  BOOLEAN;

  IF NOT _fromLeft THEN SET _input = REVERSE(_input); END IF;
  _loop: REPEAT
    SET _IsCharNumeric = LOCATE(MID(_input, _i, 1), "0123456789") > 0;
    IF _IsCharNumeric THEN
      IF _start = 0 THEN SET _start  = _i;  END IF;
    ELSE
      IF _start > 0 THEN LEAVE _loop;       END IF;
    END IF;
    SET _i = _i + 1;
  UNTIL _i > length(_input) END REPEAT;

  IF _start > 0 THEN
    SET _r = MID(_input, _start, _i - _start);
    IF NOT _fromLeft THEN SET _r = REVERSE(_r);  END IF;
  END IF;
  RETURN _r;
END$$
2
répondu m227 2013-04-28 10:30:13

Si vous voulez retourner une partie d'une chaîne de caractères :

SELECT id , substring(columnName,(locate('partOfString',columnName)),10) from tableName;

Locate() renvoie la position de départ de la chaîne correspondante qui devient la position de départ de Function Substring()

0
répondu U.Sharma 2017-12-22 19:32:56

je sais que cela fait longtemps que cette question a été posée, mais je l'ai trouvée et j'ai pensé que ce serait un bon défi pour mon remplaçant regex personnalisé - voir ce billet de blog .

...Et la bonne nouvelle est qu'il peut, bien qu'il doive être appelé plusieurs fois. Voir cette démo en ligne de rextester , qui montre les rouages qui sont arrivés au SQL ci-dessous.

SELECT reg_replace(
         reg_replace(
           reg_replace(
             reg_replace(
               reg_replace(
                 reg_replace(
                   reg_replace(txt,
                               '[^0-9]+',
                               ',',
                               TRUE,
                               1, -- Min match length
                               0 -- No max match length
                               ),
                             '([0-9]{3,}|,[0-9],)',
                             '',
                             TRUE,
                             1, -- Min match length
                             0 -- No max match length
                             ),
                           '^[0-9],',
                           '',
                           TRUE,
                           1, -- Min match length
                           0 -- No max match length
                           ),
                         ',[0-9]$',
                         '',
                         TRUE,
                         1, -- Min match length
                         0 -- No max match length
                         ),
                       ',{2,}',
                       ',',
                       TRUE,
                       1, -- Min match length
                       0 -- No max match length
                       ),
                     '^,',
                     '',
                     TRUE,
                     1, -- Min match length
                     0 -- No max match length
                     ),
                   ',$',
                   '',
                   TRUE,
                   1, -- Min match length
                   0 -- No max match length
                   ) AS `csv`
FROM tbl;
0
répondu Steve Chambers 2018-02-15 13:50:27