LPAD和REGEXP_REPLACE的互动变得不稳定?

时间:2015-11-30 14:39:25

标签: regex oracle

在这里得到了一些我无法解释的东西,希望得到一些帮助,看看我显然缺少的东西:)

在研究此问题的解决方案时: Oracle SQL to Sort Version Numbers

我认为聪明的regexp_replace + LPAD会产生更好的排序值。然而,出于某种原因,LPAD一直行为不端。这是简化测试中的“问题”:

  with w_data as (
     select '9'  v  from dual union all
     select '18' v  from dual
     )
  select v,
         lpad(v, 4, '0' ) a,
         regexp_replace(v, '([0-9]*)', lpad('\1', 4, '0')) b
  from w_data
  /

  V  
  -- 
  A
  ----
  B
  ----------
  9  
  0009
  00900

  18 
  0018
  001800


  2 rows selected.

所以你可以看到,列“a”表现得如预期的那样..一个长度为4的字符串,左边有0个填充...

然而,一旦它通过regexp_replace ......它开始变得奇怪......为什么它会像那样? 如何“正确”使用它与regexp_replace一起使用? (请注意,我的正则表达式和字符串 - 根据链接的问题 - 有点复杂;)

[编辑] 尝试用“[0-9] +”..但仍然没有正确填充..

  with w_data as (
     select '9'  v  from dual union all
     select '18' v  from dual
     )
  select v,
         lpad(v, 4, '0' ) a,
         regexp_replace(v, '([0-9]+)', lpad('\1', 4, '0')) b
  from w_data
  /

  V  
  -- 
  A
  ----
  B
  ----------
  9  
  0009
  009

  18 
  0018
  0018


  2 rows selected.

请注意18正确显示(“0018”),然而,9出现为“009”只有3个字符?应该是四个:“0009”......

2 个答案:

答案 0 :(得分:1)

LPAD不理解正则表达式替换的特殊语法;只有在直接传递给REGEXP函数时才有意义。所以这个表达式:

lpad('\1', 4, '0')

只是返回字符串'00 \ 1'。然后将该字符串传递给REGEXP_REPLACE,后者解释正则表达式上下文中的“\ 1”。

答案 1 :(得分:1)

如果您确定所有数字都不超过4位数,您可以使用:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

struct n
{
char *data;
struct n *left;
struct n*right;
};

typedef struct n node;

void in_Order(node *root)
{
if (root == NULL)
    return;

printf("%s ", root->data); 
in_Order(root->left);
in_Order(root->right);
}

int compare(node *root, char data[14])
{
if (strcmp(root->data, data) <= 0)
    return 1;
else return -1;
}
node *getNewNode(char *data)
{
node *newNode = (node *)malloc(sizeof(node));
newNode->left = NULL;
newNode->right = NULL;
newNode->data = data;
return newNode;
}

node *insert(node *root, char *data)
{
if (root == NULL)
{
    root = getNewNode(data);
    return root;
}
if (compare(root,data) == 1)
    root->left = insert(root->left, data);
else 
    root->right = insert(root->right, data);

return root;

}

int main()
{
node *root = NULL;
FILE *fptr = fopen("File.txt", "r");
char *buffer = (char *)malloc(sizeof(char)*15);
int status;

do
{
    fscanf(fptr, "%s", buffer);
    root = insert(root, buffer);
} while (status = fgetc(fptr) != EOF);

in_Order(root);

}

如果没有,这里有更复杂的解决方案:

with w_data as (
   select '9'  v  from dual union all
   select '18' v  from dual
   )
select v,
       REGEXP_REPLACE(
         REGEXP_REPLACE(v, '([0-9]+)', '000\1'),
         '(0*)([0-9]{4})', 
         '\2') b
from w_data